From 31fd5abf97f9c77919ed9fa10a147a8b6c2fed80 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Fri, 4 Aug 2023 10:19:02 -0700 Subject: [PATCH] Samples as tests (#2215) fix [#3017](https://github.com/Azure/typespec-azure/issues/3017) Run the samples as test which allows all of them to run without crashing on the first one, lets us run it in the test explorer. This also make the sample regeneration much faster(typespec azure repo): - Before `~90s` - Now `~12s` ![image](https://github.com/microsoft/typespec/assets/1031227/a3356a90-7847-43cf-a473-4ecda0c53330) ## New `resolveCompilerOptions` utils This also include the addition of a new util `resolveCompilerOptions` that resolve the compiler options programtically in the same way that the cli would have for a given entrypoint. I can move this into a dedicated PR if people prefer. --------- Co-authored-by: Mark Cowlishaw --- .prettierignore | 2 +- .vscode/settings.json | 1 + CONTRIBUTING.md | 2 +- ...mples-snapshot-tests_2023-08-03-15-54.json | 10 + common/config/rush/pnpm-lock.yaml | 18 ++ eng/pipelines/pull-request-common.yml | 3 - .../compiler/src/config/config-to-options.ts | 96 ++++++++ packages/compiler/src/config/index.ts | 1 + .../src/core/cli/actions/compile/args.ts | 120 +++------ packages/compiler/src/index.ts | 1 + packages/compiler/test/cli.test.ts | 6 +- packages/samples/.eslintrc.cjs | 7 + packages/samples/.mocharc.yaml | 4 + packages/samples/README.md | 10 + packages/samples/package.json | 17 +- .../rest-metadata-emitter/tspconfig.yaml | 2 - packages/samples/scripts/regen-samples.js | 83 ------- .../{ => specs}/authentication/main.tsp | 0 .../samples/{ => specs}/binary/binary.tsp | 0 packages/samples/{ => specs}/binary/main.tsp | 0 .../{ => specs}/documentation/docs.tsp | 0 .../{ => specs}/documentation/main.tsp | 0 .../samples/{ => specs}/encoding/encoding.tsp | 0 .../samples/{ => specs}/encoding/main.tsp | 0 .../{ => specs}/grpc-kiosk-example/README.md | 0 .../grpc-kiosk-example/kiosk.proto | 0 .../grpc-kiosk-example/kiosk.swagger.json | 0 .../{ => specs}/grpc-kiosk-example/kiosk.tsp | 0 .../{ => specs}/grpc-kiosk-example/main.tsp | 0 .../grpc-kiosk-example/openapi.json | 0 .../{ => specs}/grpc-kiosk-example/types.tsp | 0 .../grpc-library-example/README.md | 0 .../grpc-library-example/library.proto | 0 .../grpc-library-example/library.swagger.json | 0 .../grpc-library-example/library.tsp | 0 .../{ => specs}/grpc-library-example/main.tsp | 0 .../grpc-library-example/openapi.json | 0 .../local-typespec/.vscode/settings.json | 0 .../{ => specs}/local-typespec/README.md | 0 .../{ => specs}/local-typespec/main.tsp | 0 .../{ => specs}/local-typespec/package.json | 0 .../{ => specs}/local-typespec/test.tsp | 0 .../{ => specs}/multiple-types-union/main.tsp | 0 packages/samples/{ => specs}/nested/main.tsp | 0 .../samples/{ => specs}/nested/nested.tsp | 0 .../samples/{ => specs}/nullable/main.tsp | 0 .../samples/{ => specs}/nullable/nullable.tsp | 0 .../{ => specs}/openapi-extensions/main.tsp | 0 .../openapi-extensions/openapi-extensions.tsp | 0 .../samples/{ => specs}/optional/main.tsp | 0 .../samples/{ => specs}/optional/optional.tsp | 0 .../{ => specs}/param-decorators/main.tsp | 0 .../param-decorators/param-decorators.tsp | 0 .../{ => specs}/petstore/decorators.js | 0 .../samples/{ => specs}/petstore/notes.md | 0 .../samples/{ => specs}/petstore/package.json | 0 .../{ => specs}/petstore/petstore.json | 0 .../samples/{ => specs}/petstore/petstore.tsp | 0 .../samples/{ => specs}/polymorphism/main.tsp | 0 .../{ => specs}/polymorphism/polymorphism.tsp | 0 .../{ => specs}/projected-names/main.tsp | 0 .../projected-names/projected-names.tsp | 0 .../rest-metadata-emitter/main.tsp | 0 .../rest-metadata-emitter-sample.ts | 0 .../rest-metadata-emitter/tspconfig.yaml | 2 + .../{ => specs}/rest/petstore/package.json | 0 .../{ => specs}/rest/petstore/petstore.tsp | 0 .../samples/{ => specs}/signatures/main.tsp | 0 .../{ => specs}/signatures/signatures.tsp | 0 packages/samples/{ => specs}/simple/main.tsp | 0 .../samples/{ => specs}/simple/simple.tsp | 0 packages/samples/{ => specs}/tags/main.tsp | 0 .../{ => specs}/tags/tagged-operations.tsp | 0 .../testserver/body-boolean/body-boolean.tsp | 0 .../testserver/body-boolean/main.tsp | 0 .../testserver/body-complex/body-complex.tsp | 0 .../testserver/body-complex/main.tsp | 0 .../testserver/body-string/body-string.tsp | 0 .../testserver/body-string/main.tsp | 0 .../testserver/body-time/body-time.tsp | 0 .../{ => specs}/testserver/body-time/main.tsp | 0 .../testserver/media-types/main.tsp | 0 .../testserver/media-types/media-types.tsp | 0 .../testserver/multiple-inheritance/main.tsp | 0 .../multiple-inheritance.tsp | 0 .../{ => specs}/use-versioned-lib/library.tsp | 0 .../{ => specs}/use-versioned-lib/main.tsp | 0 .../{ => specs}/versioning/library.tsp | 0 .../samples/{ => specs}/versioning/main.tsp | 0 .../samples/{ => specs}/visibility/main.tsp | 0 .../{ => specs}/visibility/visibility.tsp | 0 packages/samples/src/index.ts | 1 + .../samples/src/sample-snapshot-testing.ts | 229 ++++++++++++++++++ .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 .../{ => @typespec/openapi3}/openapi.v1.yaml | 0 .../{ => @typespec/openapi3}/openapi.v2.yaml | 0 .../{ => @typespec/openapi3}/openapi.yaml | 0 packages/samples/test/samples.test.ts | 20 ++ packages/samples/tsconfig.json | 4 +- 124 files changed, 458 insertions(+), 181 deletions(-) create mode 100644 common/changes/@typespec/compiler/feature-samples-snapshot-tests_2023-08-03-15-54.json create mode 100644 packages/compiler/src/config/config-to-options.ts create mode 100644 packages/samples/.eslintrc.cjs create mode 100644 packages/samples/.mocharc.yaml delete mode 100644 packages/samples/rest-metadata-emitter/tspconfig.yaml delete mode 100644 packages/samples/scripts/regen-samples.js rename packages/samples/{ => specs}/authentication/main.tsp (100%) rename packages/samples/{ => specs}/binary/binary.tsp (100%) rename packages/samples/{ => specs}/binary/main.tsp (100%) rename packages/samples/{ => specs}/documentation/docs.tsp (100%) rename packages/samples/{ => specs}/documentation/main.tsp (100%) rename packages/samples/{ => specs}/encoding/encoding.tsp (100%) rename packages/samples/{ => specs}/encoding/main.tsp (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/README.md (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/kiosk.proto (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/kiosk.swagger.json (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/kiosk.tsp (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/main.tsp (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/openapi.json (100%) rename packages/samples/{ => specs}/grpc-kiosk-example/types.tsp (100%) rename packages/samples/{ => specs}/grpc-library-example/README.md (100%) rename packages/samples/{ => specs}/grpc-library-example/library.proto (100%) rename packages/samples/{ => specs}/grpc-library-example/library.swagger.json (100%) rename packages/samples/{ => specs}/grpc-library-example/library.tsp (100%) rename packages/samples/{ => specs}/grpc-library-example/main.tsp (100%) rename packages/samples/{ => specs}/grpc-library-example/openapi.json (100%) rename packages/samples/{ => specs}/local-typespec/.vscode/settings.json (100%) rename packages/samples/{ => specs}/local-typespec/README.md (100%) rename packages/samples/{ => specs}/local-typespec/main.tsp (100%) rename packages/samples/{ => specs}/local-typespec/package.json (100%) rename packages/samples/{ => specs}/local-typespec/test.tsp (100%) rename packages/samples/{ => specs}/multiple-types-union/main.tsp (100%) rename packages/samples/{ => specs}/nested/main.tsp (100%) rename packages/samples/{ => specs}/nested/nested.tsp (100%) rename packages/samples/{ => specs}/nullable/main.tsp (100%) rename packages/samples/{ => specs}/nullable/nullable.tsp (100%) rename packages/samples/{ => specs}/openapi-extensions/main.tsp (100%) rename packages/samples/{ => specs}/openapi-extensions/openapi-extensions.tsp (100%) rename packages/samples/{ => specs}/optional/main.tsp (100%) rename packages/samples/{ => specs}/optional/optional.tsp (100%) rename packages/samples/{ => specs}/param-decorators/main.tsp (100%) rename packages/samples/{ => specs}/param-decorators/param-decorators.tsp (100%) rename packages/samples/{ => specs}/petstore/decorators.js (100%) rename packages/samples/{ => specs}/petstore/notes.md (100%) rename packages/samples/{ => specs}/petstore/package.json (100%) rename packages/samples/{ => specs}/petstore/petstore.json (100%) rename packages/samples/{ => specs}/petstore/petstore.tsp (100%) rename packages/samples/{ => specs}/polymorphism/main.tsp (100%) rename packages/samples/{ => specs}/polymorphism/polymorphism.tsp (100%) rename packages/samples/{ => specs}/projected-names/main.tsp (100%) rename packages/samples/{ => specs}/projected-names/projected-names.tsp (100%) rename packages/samples/{ => specs}/rest-metadata-emitter/main.tsp (100%) rename packages/samples/{ => specs}/rest-metadata-emitter/rest-metadata-emitter-sample.ts (100%) create mode 100644 packages/samples/specs/rest-metadata-emitter/tspconfig.yaml rename packages/samples/{ => specs}/rest/petstore/package.json (100%) rename packages/samples/{ => specs}/rest/petstore/petstore.tsp (100%) rename packages/samples/{ => specs}/signatures/main.tsp (100%) rename packages/samples/{ => specs}/signatures/signatures.tsp (100%) rename packages/samples/{ => specs}/simple/main.tsp (100%) rename packages/samples/{ => specs}/simple/simple.tsp (100%) rename packages/samples/{ => specs}/tags/main.tsp (100%) rename packages/samples/{ => specs}/tags/tagged-operations.tsp (100%) rename packages/samples/{ => specs}/testserver/body-boolean/body-boolean.tsp (100%) rename packages/samples/{ => specs}/testserver/body-boolean/main.tsp (100%) rename packages/samples/{ => specs}/testserver/body-complex/body-complex.tsp (100%) rename packages/samples/{ => specs}/testserver/body-complex/main.tsp (100%) rename packages/samples/{ => specs}/testserver/body-string/body-string.tsp (100%) rename packages/samples/{ => specs}/testserver/body-string/main.tsp (100%) rename packages/samples/{ => specs}/testserver/body-time/body-time.tsp (100%) rename packages/samples/{ => specs}/testserver/body-time/main.tsp (100%) rename packages/samples/{ => specs}/testserver/media-types/main.tsp (100%) rename packages/samples/{ => specs}/testserver/media-types/media-types.tsp (100%) rename packages/samples/{ => specs}/testserver/multiple-inheritance/main.tsp (100%) rename packages/samples/{ => specs}/testserver/multiple-inheritance/multiple-inheritance.tsp (100%) rename packages/samples/{ => specs}/use-versioned-lib/library.tsp (100%) rename packages/samples/{ => specs}/use-versioned-lib/main.tsp (100%) rename packages/samples/{ => specs}/versioning/library.tsp (100%) rename packages/samples/{ => specs}/versioning/main.tsp (100%) rename packages/samples/{ => specs}/visibility/main.tsp (100%) rename packages/samples/{ => specs}/visibility/visibility.tsp (100%) create mode 100644 packages/samples/src/index.ts create mode 100644 packages/samples/src/sample-snapshot-testing.ts rename packages/samples/test/output/authentication/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/binary/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/documentation/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/encoding/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/grpc-kiosk-example/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/grpc-library-example/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/multiple-types-union/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/nested/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/nullable/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/openapi-extensions/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/optional/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/param-decorators/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/petstore/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/polymorphism/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/projected-names/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/rest/petstore/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/signatures/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/simple/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/tags/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/body-boolean/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/body-complex/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/body-string/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/body-time/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/media-types/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/testserver/multiple-inheritance/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/use-versioned-lib/{ => @typespec/openapi3}/openapi.yaml (100%) rename packages/samples/test/output/versioning/{ => @typespec/openapi3}/openapi.v1.yaml (100%) rename packages/samples/test/output/versioning/{ => @typespec/openapi3}/openapi.v2.yaml (100%) rename packages/samples/test/output/visibility/{ => @typespec/openapi3}/openapi.yaml (100%) create mode 100644 packages/samples/test/samples.test.ts diff --git a/.prettierignore b/.prettierignore index bdd8dbc70..1c75f4825 100644 --- a/.prettierignore +++ b/.prettierignore @@ -24,7 +24,7 @@ CODE_OF_CONDUCT.md packages/compiler/test/formatter/**/*.tsp # That is an example with error and can't be formatted -packages/samples/local-typespec/test.tsp +packages/samples/specs/local-typespec/test.tsp packages/website/build/ packages/website/versioned_sidebars/ packages/website/versions.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 82008ba98..4bd4872b1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -91,6 +91,7 @@ }, "typescript.tsdk": "./packages/compiler/node_modules/typescript/lib", "git.ignoreLimitWarning": true, + "testExplorer.useNativeTesting": true, "mochaExplorer.parallel": false, "mochaExplorer.files": [ "./packages/*/dist/test/**/*.test.js", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 42f7dd95b..87e4b408f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -209,7 +209,7 @@ debug the last one you chose. attach to both the VS Code client process and the language server process automatically. 2. **Compile Scratch**: Use this to debug compiling - `packages/typespec-samples/scratch/*.tsp`. The TypeSpec source code in that + `packages/samples/scratch/*.tsp`. The TypeSpec source code in that folder is excluded from source control by design. Create TypeSpec files there to experiment and debug how the compiler reacts. 3. **Compile Scratch (nostdlib)**: Same as above, but skips parsing diff --git a/common/changes/@typespec/compiler/feature-samples-snapshot-tests_2023-08-03-15-54.json b/common/changes/@typespec/compiler/feature-samples-snapshot-tests_2023-08-03-15-54.json new file mode 100644 index 000000000..1c1b3a7a2 --- /dev/null +++ b/common/changes/@typespec/compiler/feature-samples-snapshot-tests_2023-08-03-15-54.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/compiler", + "comment": "Add a new util `resolveCompilerOptions` to resolve compiler options from a given entrypoint. This will resolve the options from the tspconfig.yaml in the same way the cli would.", + "type": "none" + } + ], + "packageName": "@typespec/compiler" +} diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 949b174a3..7da4e8403 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -1183,12 +1183,30 @@ importers: specifier: workspace:~0.46.0 version: link:../versioning devDependencies: + '@types/mocha': + specifier: ~10.0.1 + version: 10.0.1 + '@types/node': + specifier: ~18.11.9 + version: 18.11.9 + '@typespec/eslint-config-typespec': + specifier: workspace:~0.46.0 + version: link:../eslint-config-typespec '@typespec/internal-build-utils': specifier: workspace:~0.46.0 version: link:../internal-build-utils autorest: specifier: ~3.3.2 version: 3.3.2 + cross-env: + specifier: ~7.0.3 + version: 7.0.3 + eslint: + specifier: ^8.42.0 + version: 8.42.0 + mocha: + specifier: ~10.2.0 + version: 10.2.0 rimraf: specifier: ~5.0.1 version: 5.0.1 diff --git a/eng/pipelines/pull-request-common.yml b/eng/pipelines/pull-request-common.yml index d46730fdb..6196ec971 100644 --- a/eng/pipelines/pull-request-common.yml +++ b/eng/pipelines/pull-request-common.yml @@ -46,9 +46,6 @@ steps: displayName: Lint condition: ne(variables['Agent.OS'], 'Windows_NT') - - script: cd packages/samples && npm run regen-samples - displayName: Regenerate Samples - - script: node eng/scripts/check-for-changed-files.js displayName: Check Git Status For Changed Files diff --git a/packages/compiler/src/config/config-to-options.ts b/packages/compiler/src/config/config-to-options.ts new file mode 100644 index 000000000..966ba290a --- /dev/null +++ b/packages/compiler/src/config/config-to-options.ts @@ -0,0 +1,96 @@ +import { createDiagnosticCollector, getDirectoryPath, normalizePath } from "../core/index.js"; +import { CompilerOptions } from "../core/options.js"; +import { CompilerHost, Diagnostic } from "../core/types.js"; +import { deepClone, omitUndefined } from "../core/util.js"; +import { expandConfigVariables } from "./config-interpolation.js"; +import { loadTypeSpecConfigForPath, validateConfigPathsAbsolute } from "./config-loader.js"; +import { EmitterOptions, TypeSpecConfig } from "./types.js"; + +export interface ResolveCompilerOptionsOptions { + /** Absolute entrypoint path */ + entrypoint: string; + + /** Explicit config path. */ + configPath?: string; + + /** Current working directory. This will be used to interpolate `{cwd}` in the config. + * @default to `process.cwd()` + */ + cwd?: string; + + /** + * Environment variables. + * @default process.env + */ + env?: Record; + + /** + * Any arguments to interpolate the config. + */ + args?: Record; + + /** Compiler options to override the config */ + overrides?: Partial; +} + +/** + * Resolve the compiler options for the given entrypoint by resolving the tspconfig.yaml. + * @param host Compiler host + * @param compilerOptions + */ +export async function resolveCompilerOptions( + host: CompilerHost, + options: ResolveCompilerOptionsOptions +): Promise<[CompilerOptions, readonly Diagnostic[]]> { + const cwd = normalizePath(options.cwd ?? process.cwd()); + const diagnostics = createDiagnosticCollector(); + + const entrypointStat = await host.stat(options.entrypoint); + const configPath = + options.configPath ?? entrypointStat.isDirectory() + ? options.entrypoint + : getDirectoryPath(options.entrypoint); + const config = await loadTypeSpecConfigForPath(host, configPath); + const configWithOverrides: TypeSpecConfig = { + ...config, + ...options.overrides, + options: mergeOptions(config.options, options.overrides?.options), + }; + const expandedConfig = diagnostics.pipe( + expandConfigVariables(configWithOverrides, { + cwd, + outputDir: options.overrides?.outputDir, + env: options.env ?? process.env, + args: options.args, + }) + ); + validateConfigPathsAbsolute(expandedConfig).forEach((x) => diagnostics.add(x)); + + const resolvedOptions: CompilerOptions = omitUndefined({ + outputDir: expandedConfig.outputDir, + config: config.filename, + additionalImports: expandedConfig["imports"], + warningAsError: expandedConfig.warnAsError, + trace: expandedConfig.trace, + emit: expandedConfig.emit, + options: expandedConfig.options, + linterRuleSet: expandedConfig.linter, + }); + return diagnostics.wrap(resolvedOptions); +} + +function mergeOptions( + base: Record> | undefined, + overrides: Record> | undefined +): Record { + const configuredEmitters: Record> = deepClone(base ?? {}); + + for (const [emitterName, cliOptionOverride] of Object.entries(overrides ?? {})) { + configuredEmitters[emitterName] = { + ...(configuredEmitters[emitterName] ?? {}), + ...cliOptionOverride, + }; + } + + return configuredEmitters; +} diff --git a/packages/compiler/src/config/index.ts b/packages/compiler/src/config/index.ts index f66db80ca..6755e4bfc 100644 --- a/packages/compiler/src/config/index.ts +++ b/packages/compiler/src/config/index.ts @@ -1,2 +1,3 @@ export * from "./config-loader.js"; +export { ResolveCompilerOptionsOptions, resolveCompilerOptions } from "./config-to-options.js"; export * from "./types.js"; diff --git a/packages/compiler/src/core/cli/actions/compile/args.ts b/packages/compiler/src/core/cli/actions/compile/args.ts index f9c0326a6..00520f86d 100644 --- a/packages/compiler/src/core/cli/actions/compile/args.ts +++ b/packages/compiler/src/core/cli/actions/compile/args.ts @@ -1,14 +1,9 @@ -import { expandConfigVariables } from "../../../../config/config-interpolation.js"; -import { - loadTypeSpecConfigForPath, - validateConfigPathsAbsolute, -} from "../../../../config/config-loader.js"; -import { EmitterOptions, TypeSpecConfig } from "../../../../config/types.js"; -import { createDiagnosticCollector } from "../../../index.js"; +import { resolveCompilerOptions } from "../../../../config/config-to-options.js"; +import { createDiagnosticCollector } from "../../../diagnostics.js"; import { CompilerOptions } from "../../../options.js"; -import { getDirectoryPath, normalizePath, resolvePath } from "../../../path-utils.js"; +import { resolvePath } from "../../../path-utils.js"; import { CompilerHost, Diagnostic } from "../../../types.js"; -import { deepClone, omitUndefined } from "../../../util.js"; +import { omitUndefined } from "../../../util.js"; export interface CompileCliArgs { "output-dir"?: string; @@ -34,65 +29,39 @@ export async function getCompilerOptions( args: CompileCliArgs, env: Record ): Promise<[CompilerOptions | undefined, readonly Diagnostic[]]> { - cwd = normalizePath(cwd); - const diagnostics = createDiagnosticCollector(); + const pathArg = args["output-dir"] ?? args["output-path"]; - const configPath = args["config"] - ? resolvePath(cwd, args["config"]) - : getDirectoryPath(entrypoint); - - const config = await loadTypeSpecConfigForPath(host, configPath, "config" in args); - if (config.diagnostics.length > 0) { - if (config.diagnostics.some((d) => d.severity === "error")) { - return [undefined, config.diagnostics]; - } - config.diagnostics.forEach((x) => diagnostics.add(x)); - } - - const cliOptions = resolveCliOptions(args); - - const configWithCliArgs: TypeSpecConfig = { - ...config, - outputDir: config.outputDir, - imports: args["import"] ?? config["imports"], - warnAsError: args["warn-as-error"] ?? config.warnAsError, - trace: args.trace ?? config.trace, - emit: args.emit ?? config.emit, - options: resolveEmitterOptions(config, cliOptions), - }; const cliOutputDir = pathArg ? pathArg.startsWith("{") ? pathArg : resolvePath(cwd, pathArg) : undefined; - const expandedConfig = diagnostics.pipe( - expandConfigVariables(configWithCliArgs, { - cwd: cwd, - outputDir: cliOutputDir, - env, + const cliOptions = resolveCliOptions(args); + const resolvedOptions = diagnostics.pipe( + await resolveCompilerOptions(host, { + entrypoint, + configPath: args["config"] && resolvePath(cwd, args["config"]), + cwd, args: resolveConfigArgs(args), + env, + overrides: omitUndefined({ + outputDir: cliOutputDir, + imports: args["import"], + warnAsError: args["warn-as-error"], + trace: args.trace, + emit: args.emit, + options: cliOptions.options, + }), + }) + ); + return diagnostics.wrap( + omitUndefined({ + ...resolvedOptions, + miscOptions: cliOptions.miscOptions, }) ); - validateConfigPathsAbsolute(expandedConfig).forEach((x) => diagnostics.add(x)); - - const options: CompilerOptions = omitUndefined({ - nostdlib: args["nostdlib"], - watchForChanges: args["watch"], - noEmit: args["no-emit"], - ignoreDeprecated: args["ignore-deprecated"], - miscOptions: cliOptions.miscOptions, - outputDir: expandedConfig.outputDir, - config: config.filename, - additionalImports: expandedConfig["imports"], - warningAsError: expandedConfig.warnAsError, - trace: expandedConfig.trace, - emit: expandedConfig.emit, - options: expandedConfig.options, - linterRuleSet: expandedConfig.linter, - }); - return diagnostics.wrap(options); } function resolveConfigArgs(args: CompileCliArgs): Record { @@ -108,9 +77,11 @@ function resolveConfigArgs(args: CompileCliArgs): Record { return map; } -function resolveCliOptions( - args: CompileCliArgs -): Record> { +function resolveCliOptions(args: CompileCliArgs): { + options: Record>; + miscOptions: Record | undefined; +} { + let miscOptions: Record | undefined; const options: Record> = {}; for (const option of args.options ?? []) { const optionParts = option.split("="); @@ -122,10 +93,10 @@ function resolveCliOptions( let optionKeyParts = optionParts[0].split("."); if (optionKeyParts.length === 1) { const key = optionKeyParts[0]; - if (!("miscOptions" in options)) { - options.miscOptions = {}; + if (miscOptions === undefined) { + miscOptions = {}; } - options.miscOptions[key] = optionParts[1]; + miscOptions[key] = optionParts[1]; continue; } else if (optionKeyParts.length > 2) { // support emitter/path/file.js.option=xyz @@ -141,26 +112,5 @@ function resolveCliOptions( } options[emitterName][key] = optionParts[1]; } - return options; -} - -function resolveEmitterOptions( - config: TypeSpecConfig, - cliOptions: Record> -): Record { - const configuredEmitters: Record> = deepClone( - config.options ?? {} - ); - - for (const [emitterName, cliOptionOverride] of Object.entries(cliOptions)) { - if (emitterName === "miscOptions") { - continue; - } - configuredEmitters[emitterName] = { - ...(configuredEmitters[emitterName] ?? {}), - ...cliOptionOverride, - }; - } - - return configuredEmitters; + return { options, miscOptions }; } diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index c800bc83b..b3e29aa84 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -1,3 +1,4 @@ +export { ResolveCompilerOptionsOptions, resolveCompilerOptions } from "./config/index.js"; export * from "./core/index.js"; export * from "./lib/decorators.js"; export * as decorators from "./lib/decorators.js"; diff --git a/packages/compiler/test/cli.test.ts b/packages/compiler/test/cli.test.ts index 1fcffe101..126334cf3 100644 --- a/packages/compiler/test/cli.test.ts +++ b/packages/compiler/test/cli.test.ts @@ -25,7 +25,7 @@ describe("compiler: cli", () => { async function resolveCompilerOptions(args: CompileCliArgs, env: Record = {}) { const [options, diagnostics] = await getCompilerOptions( host.compilerHost, - "ws/main.cadl", + "ws/main.tsp", cwd, args, env @@ -139,7 +139,7 @@ describe("compiler: cli", () => { it("emit diagnostic if passing unknown parameter", async () => { const [_, diagnostics] = await getCompilerOptions( host.compilerHost, - "ws/main.cadl", + "ws/main.tsp", cwd, { args: ["not-defined-arg=my-value"], @@ -162,7 +162,7 @@ describe("compiler: cli", () => { ); const [_, diagnostics] = await getCompilerOptions( host.compilerHost, - "ws/main.cadl", + "ws/main.tsp", cwd, {}, {} diff --git a/packages/samples/.eslintrc.cjs b/packages/samples/.eslintrc.cjs new file mode 100644 index 000000000..c0b2a9d1a --- /dev/null +++ b/packages/samples/.eslintrc.cjs @@ -0,0 +1,7 @@ +require("@typespec/eslint-config-typespec/patch/modern-module-resolution"); + +module.exports = { + plugins: ["@typespec/eslint-plugin"], + extends: ["@typespec/eslint-config-typespec", "plugin:@typespec/eslint-plugin/recommended"], + parserOptions: { tsconfigRootDir: __dirname }, +}; diff --git a/packages/samples/.mocharc.yaml b/packages/samples/.mocharc.yaml new file mode 100644 index 000000000..2c757438b --- /dev/null +++ b/packages/samples/.mocharc.yaml @@ -0,0 +1,4 @@ +timeout: 5000 +require: source-map-support/register +spec: "dist/test/**/*.js" +ignore: "dist/test/manual/**/*.js" diff --git a/packages/samples/README.md b/packages/samples/README.md index b038131ed..03f0acb43 100644 --- a/packages/samples/README.md +++ b/packages/samples/README.md @@ -3,3 +3,13 @@ This project has a collection of samples used to demonstrate and test various TypeSpec features. It is not published as an npm package. + +```bash +npm run test # Check Samples match snapshots +npm run test-official # run test same as CI + + +npm run test:regen -- -g "" # Regen of this name + +npm run regen-samples # Regen all samples. +``` diff --git a/packages/samples/package.json b/packages/samples/package.json index 24f0603d7..0ebde7e86 100644 --- a/packages/samples/package.json +++ b/packages/samples/package.json @@ -19,6 +19,12 @@ "cli" ], "type": "module", + "exports": { + ".": { + "default": "./dist/src/index.js", + "types": "./dist/src/index.d.ts" + } + }, "engines": { "node": ">=16.0.0" }, @@ -26,7 +32,10 @@ "clean": "rimraf ./dist ./temp", "build": "tsc -p .", "watch": "tsc -p . --watch", - "regen-samples": "node scripts/regen-samples.js" + "test": "mocha", + "test-official": "mocha --forbid-only", + "test:regen": "cross-env RECORD=true mocha", + "regen-samples": "RECORD=true mocha" }, "files": [ "lib/*.tsp", @@ -45,6 +54,12 @@ }, "devDependencies": { "@typespec/internal-build-utils": "workspace:~0.46.0", + "@typespec/eslint-config-typespec": "workspace:~0.46.0", + "@types/mocha": "~10.0.1", + "@types/node": "~18.11.9", + "cross-env": "~7.0.3", + "eslint": "^8.42.0", + "mocha": "~10.2.0", "autorest": "~3.3.2", "rimraf": "~5.0.1", "typescript": "~5.1.3" diff --git a/packages/samples/rest-metadata-emitter/tspconfig.yaml b/packages/samples/rest-metadata-emitter/tspconfig.yaml deleted file mode 100644 index eefe88d11..000000000 --- a/packages/samples/rest-metadata-emitter/tspconfig.yaml +++ /dev/null @@ -1,2 +0,0 @@ -emit: - - ../dist/rest-emitter/rest-emitter-sample.js diff --git a/packages/samples/scripts/regen-samples.js b/packages/samples/scripts/regen-samples.js deleted file mode 100644 index 416224881..000000000 --- a/packages/samples/scripts/regen-samples.js +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env node -// @ts-check -import { run } from "@typespec/internal-build-utils"; -import { readdirSync, rmSync } from "fs"; -import { mkdir } from "fs/promises"; -import { dirname, join, normalize, resolve } from "path"; -import { fileURLToPath } from "url"; - -const excludedSamples = [ - // fails compilation by design to demo language server - "local-typespec", - - // no actual samples in these dirs - "node_modules", - "dist", - "scratch", - "scripts", - "test", - ".rush", -]; - -const rootInputPath = resolvePath("../"); -const rootOutputPath = resolvePath("../test/output"); -const restEmitterSamplePath = resolvePath("../rest-metadata-emitter"); - -main().catch((e) => { - console.error(e); - process.exit(1); -}); - -async function main() { - // clear any previous output as otherwise failing to emit anything could - // escape PR validation. Also ensures we delete output for samples that - // no longer exist. - rmSync(rootOutputPath, { recursive: true }); - - for (const folderName of getSampleFolders()) { - const inputPath = join(rootInputPath, folderName); - const outputPath = join(rootOutputPath, folderName); - await mkdir(outputPath, { recursive: true }); - - let emitter = "@typespec/openapi3"; - if (inputPath === restEmitterSamplePath) { - emitter = resolvePath("../dist/rest-metadata-emitter/rest-metadata-emitter-sample.js"); - } - - await run(process.execPath, [ - "../../packages/compiler/entrypoints/cli.js", - "compile", - inputPath, - `--option="${emitter}.emitter-output-dir=${outputPath}"`, - `--emit=${emitter}`, - `--warn-as-error`, - `--debug`, - ]); - } -} - -function getSampleFolders() { - const samples = new Set(); - const excludes = new Set(excludedSamples.map(normalize)); - walk(""); - return samples; - - function walk(relativeDir) { - if (samples.has(relativeDir) || excludes.has(relativeDir)) { - return; - } - const fullDir = join(rootInputPath, relativeDir); - for (const entry of readdirSync(fullDir, { withFileTypes: true })) { - if (entry.isDirectory()) { - walk(join(relativeDir, entry.name)); - } else if (relativeDir && (entry.name === "main.tsp" || entry.name === "package.json")) { - samples.add(relativeDir); - } - } - } -} - -function resolvePath(...parts) { - const dir = dirname(fileURLToPath(import.meta.url)); - return resolve(dir, ...parts); -} diff --git a/packages/samples/authentication/main.tsp b/packages/samples/specs/authentication/main.tsp similarity index 100% rename from packages/samples/authentication/main.tsp rename to packages/samples/specs/authentication/main.tsp diff --git a/packages/samples/binary/binary.tsp b/packages/samples/specs/binary/binary.tsp similarity index 100% rename from packages/samples/binary/binary.tsp rename to packages/samples/specs/binary/binary.tsp diff --git a/packages/samples/binary/main.tsp b/packages/samples/specs/binary/main.tsp similarity index 100% rename from packages/samples/binary/main.tsp rename to packages/samples/specs/binary/main.tsp diff --git a/packages/samples/documentation/docs.tsp b/packages/samples/specs/documentation/docs.tsp similarity index 100% rename from packages/samples/documentation/docs.tsp rename to packages/samples/specs/documentation/docs.tsp diff --git a/packages/samples/documentation/main.tsp b/packages/samples/specs/documentation/main.tsp similarity index 100% rename from packages/samples/documentation/main.tsp rename to packages/samples/specs/documentation/main.tsp diff --git a/packages/samples/encoding/encoding.tsp b/packages/samples/specs/encoding/encoding.tsp similarity index 100% rename from packages/samples/encoding/encoding.tsp rename to packages/samples/specs/encoding/encoding.tsp diff --git a/packages/samples/encoding/main.tsp b/packages/samples/specs/encoding/main.tsp similarity index 100% rename from packages/samples/encoding/main.tsp rename to packages/samples/specs/encoding/main.tsp diff --git a/packages/samples/grpc-kiosk-example/README.md b/packages/samples/specs/grpc-kiosk-example/README.md similarity index 100% rename from packages/samples/grpc-kiosk-example/README.md rename to packages/samples/specs/grpc-kiosk-example/README.md diff --git a/packages/samples/grpc-kiosk-example/kiosk.proto b/packages/samples/specs/grpc-kiosk-example/kiosk.proto similarity index 100% rename from packages/samples/grpc-kiosk-example/kiosk.proto rename to packages/samples/specs/grpc-kiosk-example/kiosk.proto diff --git a/packages/samples/grpc-kiosk-example/kiosk.swagger.json b/packages/samples/specs/grpc-kiosk-example/kiosk.swagger.json similarity index 100% rename from packages/samples/grpc-kiosk-example/kiosk.swagger.json rename to packages/samples/specs/grpc-kiosk-example/kiosk.swagger.json diff --git a/packages/samples/grpc-kiosk-example/kiosk.tsp b/packages/samples/specs/grpc-kiosk-example/kiosk.tsp similarity index 100% rename from packages/samples/grpc-kiosk-example/kiosk.tsp rename to packages/samples/specs/grpc-kiosk-example/kiosk.tsp diff --git a/packages/samples/grpc-kiosk-example/main.tsp b/packages/samples/specs/grpc-kiosk-example/main.tsp similarity index 100% rename from packages/samples/grpc-kiosk-example/main.tsp rename to packages/samples/specs/grpc-kiosk-example/main.tsp diff --git a/packages/samples/grpc-kiosk-example/openapi.json b/packages/samples/specs/grpc-kiosk-example/openapi.json similarity index 100% rename from packages/samples/grpc-kiosk-example/openapi.json rename to packages/samples/specs/grpc-kiosk-example/openapi.json diff --git a/packages/samples/grpc-kiosk-example/types.tsp b/packages/samples/specs/grpc-kiosk-example/types.tsp similarity index 100% rename from packages/samples/grpc-kiosk-example/types.tsp rename to packages/samples/specs/grpc-kiosk-example/types.tsp diff --git a/packages/samples/grpc-library-example/README.md b/packages/samples/specs/grpc-library-example/README.md similarity index 100% rename from packages/samples/grpc-library-example/README.md rename to packages/samples/specs/grpc-library-example/README.md diff --git a/packages/samples/grpc-library-example/library.proto b/packages/samples/specs/grpc-library-example/library.proto similarity index 100% rename from packages/samples/grpc-library-example/library.proto rename to packages/samples/specs/grpc-library-example/library.proto diff --git a/packages/samples/grpc-library-example/library.swagger.json b/packages/samples/specs/grpc-library-example/library.swagger.json similarity index 100% rename from packages/samples/grpc-library-example/library.swagger.json rename to packages/samples/specs/grpc-library-example/library.swagger.json diff --git a/packages/samples/grpc-library-example/library.tsp b/packages/samples/specs/grpc-library-example/library.tsp similarity index 100% rename from packages/samples/grpc-library-example/library.tsp rename to packages/samples/specs/grpc-library-example/library.tsp diff --git a/packages/samples/grpc-library-example/main.tsp b/packages/samples/specs/grpc-library-example/main.tsp similarity index 100% rename from packages/samples/grpc-library-example/main.tsp rename to packages/samples/specs/grpc-library-example/main.tsp diff --git a/packages/samples/grpc-library-example/openapi.json b/packages/samples/specs/grpc-library-example/openapi.json similarity index 100% rename from packages/samples/grpc-library-example/openapi.json rename to packages/samples/specs/grpc-library-example/openapi.json diff --git a/packages/samples/local-typespec/.vscode/settings.json b/packages/samples/specs/local-typespec/.vscode/settings.json similarity index 100% rename from packages/samples/local-typespec/.vscode/settings.json rename to packages/samples/specs/local-typespec/.vscode/settings.json diff --git a/packages/samples/local-typespec/README.md b/packages/samples/specs/local-typespec/README.md similarity index 100% rename from packages/samples/local-typespec/README.md rename to packages/samples/specs/local-typespec/README.md diff --git a/packages/samples/local-typespec/main.tsp b/packages/samples/specs/local-typespec/main.tsp similarity index 100% rename from packages/samples/local-typespec/main.tsp rename to packages/samples/specs/local-typespec/main.tsp diff --git a/packages/samples/local-typespec/package.json b/packages/samples/specs/local-typespec/package.json similarity index 100% rename from packages/samples/local-typespec/package.json rename to packages/samples/specs/local-typespec/package.json diff --git a/packages/samples/local-typespec/test.tsp b/packages/samples/specs/local-typespec/test.tsp similarity index 100% rename from packages/samples/local-typespec/test.tsp rename to packages/samples/specs/local-typespec/test.tsp diff --git a/packages/samples/multiple-types-union/main.tsp b/packages/samples/specs/multiple-types-union/main.tsp similarity index 100% rename from packages/samples/multiple-types-union/main.tsp rename to packages/samples/specs/multiple-types-union/main.tsp diff --git a/packages/samples/nested/main.tsp b/packages/samples/specs/nested/main.tsp similarity index 100% rename from packages/samples/nested/main.tsp rename to packages/samples/specs/nested/main.tsp diff --git a/packages/samples/nested/nested.tsp b/packages/samples/specs/nested/nested.tsp similarity index 100% rename from packages/samples/nested/nested.tsp rename to packages/samples/specs/nested/nested.tsp diff --git a/packages/samples/nullable/main.tsp b/packages/samples/specs/nullable/main.tsp similarity index 100% rename from packages/samples/nullable/main.tsp rename to packages/samples/specs/nullable/main.tsp diff --git a/packages/samples/nullable/nullable.tsp b/packages/samples/specs/nullable/nullable.tsp similarity index 100% rename from packages/samples/nullable/nullable.tsp rename to packages/samples/specs/nullable/nullable.tsp diff --git a/packages/samples/openapi-extensions/main.tsp b/packages/samples/specs/openapi-extensions/main.tsp similarity index 100% rename from packages/samples/openapi-extensions/main.tsp rename to packages/samples/specs/openapi-extensions/main.tsp diff --git a/packages/samples/openapi-extensions/openapi-extensions.tsp b/packages/samples/specs/openapi-extensions/openapi-extensions.tsp similarity index 100% rename from packages/samples/openapi-extensions/openapi-extensions.tsp rename to packages/samples/specs/openapi-extensions/openapi-extensions.tsp diff --git a/packages/samples/optional/main.tsp b/packages/samples/specs/optional/main.tsp similarity index 100% rename from packages/samples/optional/main.tsp rename to packages/samples/specs/optional/main.tsp diff --git a/packages/samples/optional/optional.tsp b/packages/samples/specs/optional/optional.tsp similarity index 100% rename from packages/samples/optional/optional.tsp rename to packages/samples/specs/optional/optional.tsp diff --git a/packages/samples/param-decorators/main.tsp b/packages/samples/specs/param-decorators/main.tsp similarity index 100% rename from packages/samples/param-decorators/main.tsp rename to packages/samples/specs/param-decorators/main.tsp diff --git a/packages/samples/param-decorators/param-decorators.tsp b/packages/samples/specs/param-decorators/param-decorators.tsp similarity index 100% rename from packages/samples/param-decorators/param-decorators.tsp rename to packages/samples/specs/param-decorators/param-decorators.tsp diff --git a/packages/samples/petstore/decorators.js b/packages/samples/specs/petstore/decorators.js similarity index 100% rename from packages/samples/petstore/decorators.js rename to packages/samples/specs/petstore/decorators.js diff --git a/packages/samples/petstore/notes.md b/packages/samples/specs/petstore/notes.md similarity index 100% rename from packages/samples/petstore/notes.md rename to packages/samples/specs/petstore/notes.md diff --git a/packages/samples/petstore/package.json b/packages/samples/specs/petstore/package.json similarity index 100% rename from packages/samples/petstore/package.json rename to packages/samples/specs/petstore/package.json diff --git a/packages/samples/petstore/petstore.json b/packages/samples/specs/petstore/petstore.json similarity index 100% rename from packages/samples/petstore/petstore.json rename to packages/samples/specs/petstore/petstore.json diff --git a/packages/samples/petstore/petstore.tsp b/packages/samples/specs/petstore/petstore.tsp similarity index 100% rename from packages/samples/petstore/petstore.tsp rename to packages/samples/specs/petstore/petstore.tsp diff --git a/packages/samples/polymorphism/main.tsp b/packages/samples/specs/polymorphism/main.tsp similarity index 100% rename from packages/samples/polymorphism/main.tsp rename to packages/samples/specs/polymorphism/main.tsp diff --git a/packages/samples/polymorphism/polymorphism.tsp b/packages/samples/specs/polymorphism/polymorphism.tsp similarity index 100% rename from packages/samples/polymorphism/polymorphism.tsp rename to packages/samples/specs/polymorphism/polymorphism.tsp diff --git a/packages/samples/projected-names/main.tsp b/packages/samples/specs/projected-names/main.tsp similarity index 100% rename from packages/samples/projected-names/main.tsp rename to packages/samples/specs/projected-names/main.tsp diff --git a/packages/samples/projected-names/projected-names.tsp b/packages/samples/specs/projected-names/projected-names.tsp similarity index 100% rename from packages/samples/projected-names/projected-names.tsp rename to packages/samples/specs/projected-names/projected-names.tsp diff --git a/packages/samples/rest-metadata-emitter/main.tsp b/packages/samples/specs/rest-metadata-emitter/main.tsp similarity index 100% rename from packages/samples/rest-metadata-emitter/main.tsp rename to packages/samples/specs/rest-metadata-emitter/main.tsp diff --git a/packages/samples/rest-metadata-emitter/rest-metadata-emitter-sample.ts b/packages/samples/specs/rest-metadata-emitter/rest-metadata-emitter-sample.ts similarity index 100% rename from packages/samples/rest-metadata-emitter/rest-metadata-emitter-sample.ts rename to packages/samples/specs/rest-metadata-emitter/rest-metadata-emitter-sample.ts diff --git a/packages/samples/specs/rest-metadata-emitter/tspconfig.yaml b/packages/samples/specs/rest-metadata-emitter/tspconfig.yaml new file mode 100644 index 000000000..890f3caa4 --- /dev/null +++ b/packages/samples/specs/rest-metadata-emitter/tspconfig.yaml @@ -0,0 +1,2 @@ +emit: + - ../../dist/specs/rest-metadata-emitter/rest-metadata-emitter-sample.js diff --git a/packages/samples/rest/petstore/package.json b/packages/samples/specs/rest/petstore/package.json similarity index 100% rename from packages/samples/rest/petstore/package.json rename to packages/samples/specs/rest/petstore/package.json diff --git a/packages/samples/rest/petstore/petstore.tsp b/packages/samples/specs/rest/petstore/petstore.tsp similarity index 100% rename from packages/samples/rest/petstore/petstore.tsp rename to packages/samples/specs/rest/petstore/petstore.tsp diff --git a/packages/samples/signatures/main.tsp b/packages/samples/specs/signatures/main.tsp similarity index 100% rename from packages/samples/signatures/main.tsp rename to packages/samples/specs/signatures/main.tsp diff --git a/packages/samples/signatures/signatures.tsp b/packages/samples/specs/signatures/signatures.tsp similarity index 100% rename from packages/samples/signatures/signatures.tsp rename to packages/samples/specs/signatures/signatures.tsp diff --git a/packages/samples/simple/main.tsp b/packages/samples/specs/simple/main.tsp similarity index 100% rename from packages/samples/simple/main.tsp rename to packages/samples/specs/simple/main.tsp diff --git a/packages/samples/simple/simple.tsp b/packages/samples/specs/simple/simple.tsp similarity index 100% rename from packages/samples/simple/simple.tsp rename to packages/samples/specs/simple/simple.tsp diff --git a/packages/samples/tags/main.tsp b/packages/samples/specs/tags/main.tsp similarity index 100% rename from packages/samples/tags/main.tsp rename to packages/samples/specs/tags/main.tsp diff --git a/packages/samples/tags/tagged-operations.tsp b/packages/samples/specs/tags/tagged-operations.tsp similarity index 100% rename from packages/samples/tags/tagged-operations.tsp rename to packages/samples/specs/tags/tagged-operations.tsp diff --git a/packages/samples/testserver/body-boolean/body-boolean.tsp b/packages/samples/specs/testserver/body-boolean/body-boolean.tsp similarity index 100% rename from packages/samples/testserver/body-boolean/body-boolean.tsp rename to packages/samples/specs/testserver/body-boolean/body-boolean.tsp diff --git a/packages/samples/testserver/body-boolean/main.tsp b/packages/samples/specs/testserver/body-boolean/main.tsp similarity index 100% rename from packages/samples/testserver/body-boolean/main.tsp rename to packages/samples/specs/testserver/body-boolean/main.tsp diff --git a/packages/samples/testserver/body-complex/body-complex.tsp b/packages/samples/specs/testserver/body-complex/body-complex.tsp similarity index 100% rename from packages/samples/testserver/body-complex/body-complex.tsp rename to packages/samples/specs/testserver/body-complex/body-complex.tsp diff --git a/packages/samples/testserver/body-complex/main.tsp b/packages/samples/specs/testserver/body-complex/main.tsp similarity index 100% rename from packages/samples/testserver/body-complex/main.tsp rename to packages/samples/specs/testserver/body-complex/main.tsp diff --git a/packages/samples/testserver/body-string/body-string.tsp b/packages/samples/specs/testserver/body-string/body-string.tsp similarity index 100% rename from packages/samples/testserver/body-string/body-string.tsp rename to packages/samples/specs/testserver/body-string/body-string.tsp diff --git a/packages/samples/testserver/body-string/main.tsp b/packages/samples/specs/testserver/body-string/main.tsp similarity index 100% rename from packages/samples/testserver/body-string/main.tsp rename to packages/samples/specs/testserver/body-string/main.tsp diff --git a/packages/samples/testserver/body-time/body-time.tsp b/packages/samples/specs/testserver/body-time/body-time.tsp similarity index 100% rename from packages/samples/testserver/body-time/body-time.tsp rename to packages/samples/specs/testserver/body-time/body-time.tsp diff --git a/packages/samples/testserver/body-time/main.tsp b/packages/samples/specs/testserver/body-time/main.tsp similarity index 100% rename from packages/samples/testserver/body-time/main.tsp rename to packages/samples/specs/testserver/body-time/main.tsp diff --git a/packages/samples/testserver/media-types/main.tsp b/packages/samples/specs/testserver/media-types/main.tsp similarity index 100% rename from packages/samples/testserver/media-types/main.tsp rename to packages/samples/specs/testserver/media-types/main.tsp diff --git a/packages/samples/testserver/media-types/media-types.tsp b/packages/samples/specs/testserver/media-types/media-types.tsp similarity index 100% rename from packages/samples/testserver/media-types/media-types.tsp rename to packages/samples/specs/testserver/media-types/media-types.tsp diff --git a/packages/samples/testserver/multiple-inheritance/main.tsp b/packages/samples/specs/testserver/multiple-inheritance/main.tsp similarity index 100% rename from packages/samples/testserver/multiple-inheritance/main.tsp rename to packages/samples/specs/testserver/multiple-inheritance/main.tsp diff --git a/packages/samples/testserver/multiple-inheritance/multiple-inheritance.tsp b/packages/samples/specs/testserver/multiple-inheritance/multiple-inheritance.tsp similarity index 100% rename from packages/samples/testserver/multiple-inheritance/multiple-inheritance.tsp rename to packages/samples/specs/testserver/multiple-inheritance/multiple-inheritance.tsp diff --git a/packages/samples/use-versioned-lib/library.tsp b/packages/samples/specs/use-versioned-lib/library.tsp similarity index 100% rename from packages/samples/use-versioned-lib/library.tsp rename to packages/samples/specs/use-versioned-lib/library.tsp diff --git a/packages/samples/use-versioned-lib/main.tsp b/packages/samples/specs/use-versioned-lib/main.tsp similarity index 100% rename from packages/samples/use-versioned-lib/main.tsp rename to packages/samples/specs/use-versioned-lib/main.tsp diff --git a/packages/samples/versioning/library.tsp b/packages/samples/specs/versioning/library.tsp similarity index 100% rename from packages/samples/versioning/library.tsp rename to packages/samples/specs/versioning/library.tsp diff --git a/packages/samples/versioning/main.tsp b/packages/samples/specs/versioning/main.tsp similarity index 100% rename from packages/samples/versioning/main.tsp rename to packages/samples/specs/versioning/main.tsp diff --git a/packages/samples/visibility/main.tsp b/packages/samples/specs/visibility/main.tsp similarity index 100% rename from packages/samples/visibility/main.tsp rename to packages/samples/specs/visibility/main.tsp diff --git a/packages/samples/visibility/visibility.tsp b/packages/samples/specs/visibility/visibility.tsp similarity index 100% rename from packages/samples/visibility/visibility.tsp rename to packages/samples/specs/visibility/visibility.tsp diff --git a/packages/samples/src/index.ts b/packages/samples/src/index.ts new file mode 100644 index 000000000..4a2e207b0 --- /dev/null +++ b/packages/samples/src/index.ts @@ -0,0 +1 @@ +export * from "./sample-snapshot-testing.js"; diff --git a/packages/samples/src/sample-snapshot-testing.ts b/packages/samples/src/sample-snapshot-testing.ts new file mode 100644 index 000000000..352567baf --- /dev/null +++ b/packages/samples/src/sample-snapshot-testing.ts @@ -0,0 +1,229 @@ +import { + CompilerHost, + NodeHost, + ResolveCompilerOptionsOptions, + compile, + getDirectoryPath, + getRelativePathFromDirectory, + joinPaths, + resolveCompilerOptions, + resolvePath, +} from "@typespec/compiler"; +import { expectDiagnosticEmpty } from "@typespec/compiler/testing"; +import { fail, ok, strictEqual } from "assert"; +import { readdirSync } from "fs"; +import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises"; + +const shouldUpdateSnapshots = process.env.RECORD === "true"; + +export interface SampleSnapshotTestOptions { + /** Sample root directory. */ + sampleDir: string; + + /** Output directory for snapshots. */ + outputDir: string; + + /** Folders to exclude from testing. */ + exclude?: string[]; + + /** Override the emitters to use. */ + emit?: string[]; +} + +export interface TestContext { + runCount: number; + registerSnapshot(filename: string): void; +} +export function defineSampleSnaphotTests(config: SampleSnapshotTestOptions) { + const samples = resolveSamples(config); + let existingSnapshots: string[]; + const writtenSnapshots: string[] = []; + const context = { + runCount: 0, + registerSnapshot(filename: string) { + writtenSnapshots.push(filename); + }, + }; + before(async () => { + existingSnapshots = await readFilesInDirRecursively(config.outputDir); + }); + + after(async function (this: any) { + if (context.runCount !== samples.length) { + return; // Not running the full test suite, so don't bother checking snapshots. + } + + if (this.test.parent.tests.some((x: any) => x.state === "failed")) { + return; // Do not check snapshots if the test failed so we don't get a confusing error message about the missing snapshot if there is already a failure. + } + + const missingSnapshots = new Set(existingSnapshots); + for (const writtenSnapshot of writtenSnapshots) { + missingSnapshots.delete(writtenSnapshot); + } + if (missingSnapshots.size > 0) { + if (shouldUpdateSnapshots) { + for (const file of [...missingSnapshots].map((x) => joinPaths(config.outputDir, x))) { + await rm(file); + } + } else { + const snapshotList = [...missingSnapshots].map((x) => ` ${x}`).join("\n"); + fail( + `The following snapshot are still present in the output dir but were not generated:\n${snapshotList}\n Run with RECORD=true to regenerate them.` + ); + } + } + }); + samples.forEach((samples) => defineSampleSnaphotTest(context, config, samples)); +} + +function defineSampleSnaphotTest( + context: TestContext, + config: SampleSnapshotTestOptions, + sample: Sample +) { + it(sample.name, async () => { + context.runCount++; + const host = createSampleSnapshotTestHost(config); + + const outputDir = resolvePath(config.outputDir, sample.name); + + const overrides: Partial = { + outputDir, + }; + if (config.emit) { + overrides.emit = config.emit; + } + const [options, diagnostics] = await resolveCompilerOptions(host, { + entrypoint: sample.fullPath, + overrides, + }); + expectDiagnosticEmpty(diagnostics); + + 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.` + ); + } + + const program = await compile(host, sample.fullPath, options); + expectDiagnosticEmpty(program.diagnostics); + + if (shouldUpdateSnapshots) { + try { + await host.rm(outputDir, { recursive: true }); + } catch (e) {} + await mkdir(outputDir, { recursive: true }); + + for (const [snapshotPath, content] of host.outputs.entries()) { + const relativePath = getRelativePathFromDirectory(outputDir, snapshotPath, false); + + try { + await mkdir(getDirectoryPath(snapshotPath), { recursive: true }); + await writeFile(snapshotPath, content); + context.registerSnapshot(resolvePath(sample.name, relativePath)); + } catch (e) { + throw new Error(`Failure to write snapshot: "${snapshotPath}"\n Error: ${e}`); + } + } + } else { + for (const [snapshotPath, content] of host.outputs.entries()) { + const relativePath = getRelativePathFromDirectory(outputDir, snapshotPath, false); + let existingContent; + try { + existingContent = await readFile(snapshotPath); + } catch (e: unknown) { + if (isEnoentError(e)) { + fail(`Snapshot "${snapshotPath}" is missing. Run with RECORD=true to regenerate it.`); + } + throw e; + } + context.registerSnapshot(resolvePath(sample.name, relativePath)); + strictEqual(content, existingContent.toString()); + } + + for (const filename of await readFilesInDirRecursively(outputDir)) { + const snapshotPath = resolvePath(outputDir, filename); + ok( + host.outputs.has(snapshotPath), + `Snapshot for "${snapshotPath}" was not emitted. Run with RECORD=true to remove it.` + ); + } + } + }); +} + +interface SampleSnapshotTestHost extends CompilerHost { + outputs: Map; +} + +function createSampleSnapshotTestHost(config: SampleSnapshotTestOptions): SampleSnapshotTestHost { + const outputs = new Map(); + return { + ...NodeHost, + outputs, + mkdirp: (path: string) => Promise.resolve(path), + rm: (path: string) => Promise.resolve(), + writeFile: async (path: string, content: string) => { + outputs.set(path, content); + }, + }; +} +async function readFilesInDirRecursively(dir: string): Promise { + let entries; + try { + entries = await readdir(dir, { withFileTypes: true }); + } catch (e) { + if (isEnoentError(e)) { + return []; + } else { + throw new Error(`Failed to read dir "${dir}"\n Error: ${e}`); + } + } + const files: string[] = []; + for (const entry of entries) { + if (entry.isDirectory()) { + for (const file of await readFilesInDirRecursively(resolvePath(dir, entry.name))) { + files.push(resolvePath(entry.name, file)); + } + } else { + files.push(entry.name); + } + } + return files; +} + +interface Sample { + name: string; + /** Sample folder */ + fullPath: string; +} + +function resolveSamples(config: SampleSnapshotTestOptions): Sample[] { + const samples: Sample[] = []; + const excludes = new Set(config.exclude); + walk(""); + return samples; + + async function walk(relativeDir: string) { + if (excludes.has(relativeDir)) { + return; + } + const fullDir = joinPaths(config.sampleDir, relativeDir); + for (const entry of readdirSync(fullDir, { withFileTypes: true })) { + if (entry.isDirectory()) { + walk(joinPaths(relativeDir, entry.name)); + } else if (relativeDir && (entry.name === "main.tsp" || entry.name === "package.json")) { + samples.push({ + name: relativeDir, + fullPath: joinPaths(config.sampleDir, relativeDir), + }); + } + } + } +} + +function isEnoentError(e: unknown): e is { code: "ENOENT" } { + return typeof e === "object" && e !== null && "code" in e; +} diff --git a/packages/samples/test/output/authentication/openapi.yaml b/packages/samples/test/output/authentication/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/authentication/openapi.yaml rename to packages/samples/test/output/authentication/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/binary/openapi.yaml b/packages/samples/test/output/binary/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/binary/openapi.yaml rename to packages/samples/test/output/binary/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/documentation/openapi.yaml b/packages/samples/test/output/documentation/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/documentation/openapi.yaml rename to packages/samples/test/output/documentation/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/encoding/openapi.yaml b/packages/samples/test/output/encoding/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/encoding/openapi.yaml rename to packages/samples/test/output/encoding/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/grpc-kiosk-example/openapi.yaml b/packages/samples/test/output/grpc-kiosk-example/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/grpc-kiosk-example/openapi.yaml rename to packages/samples/test/output/grpc-kiosk-example/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/grpc-library-example/openapi.yaml b/packages/samples/test/output/grpc-library-example/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/grpc-library-example/openapi.yaml rename to packages/samples/test/output/grpc-library-example/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/multiple-types-union/openapi.yaml b/packages/samples/test/output/multiple-types-union/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/multiple-types-union/openapi.yaml rename to packages/samples/test/output/multiple-types-union/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/nested/openapi.yaml b/packages/samples/test/output/nested/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/nested/openapi.yaml rename to packages/samples/test/output/nested/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/nullable/openapi.yaml b/packages/samples/test/output/nullable/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/nullable/openapi.yaml rename to packages/samples/test/output/nullable/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/openapi-extensions/openapi.yaml b/packages/samples/test/output/openapi-extensions/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/openapi-extensions/openapi.yaml rename to packages/samples/test/output/openapi-extensions/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/optional/openapi.yaml b/packages/samples/test/output/optional/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/optional/openapi.yaml rename to packages/samples/test/output/optional/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/param-decorators/openapi.yaml b/packages/samples/test/output/param-decorators/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/param-decorators/openapi.yaml rename to packages/samples/test/output/param-decorators/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/petstore/openapi.yaml b/packages/samples/test/output/petstore/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/petstore/openapi.yaml rename to packages/samples/test/output/petstore/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/polymorphism/openapi.yaml b/packages/samples/test/output/polymorphism/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/polymorphism/openapi.yaml rename to packages/samples/test/output/polymorphism/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/projected-names/openapi.yaml b/packages/samples/test/output/projected-names/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/projected-names/openapi.yaml rename to packages/samples/test/output/projected-names/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/rest/petstore/openapi.yaml b/packages/samples/test/output/rest/petstore/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/rest/petstore/openapi.yaml rename to packages/samples/test/output/rest/petstore/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/signatures/openapi.yaml b/packages/samples/test/output/signatures/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/signatures/openapi.yaml rename to packages/samples/test/output/signatures/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/simple/openapi.yaml b/packages/samples/test/output/simple/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/simple/openapi.yaml rename to packages/samples/test/output/simple/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/tags/openapi.yaml b/packages/samples/test/output/tags/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/tags/openapi.yaml rename to packages/samples/test/output/tags/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/body-boolean/openapi.yaml b/packages/samples/test/output/testserver/body-boolean/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/body-boolean/openapi.yaml rename to packages/samples/test/output/testserver/body-boolean/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/body-complex/openapi.yaml b/packages/samples/test/output/testserver/body-complex/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/body-complex/openapi.yaml rename to packages/samples/test/output/testserver/body-complex/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/body-string/openapi.yaml b/packages/samples/test/output/testserver/body-string/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/body-string/openapi.yaml rename to packages/samples/test/output/testserver/body-string/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/body-time/openapi.yaml b/packages/samples/test/output/testserver/body-time/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/body-time/openapi.yaml rename to packages/samples/test/output/testserver/body-time/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/media-types/openapi.yaml b/packages/samples/test/output/testserver/media-types/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/media-types/openapi.yaml rename to packages/samples/test/output/testserver/media-types/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/testserver/multiple-inheritance/openapi.yaml b/packages/samples/test/output/testserver/multiple-inheritance/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/testserver/multiple-inheritance/openapi.yaml rename to packages/samples/test/output/testserver/multiple-inheritance/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/use-versioned-lib/openapi.yaml b/packages/samples/test/output/use-versioned-lib/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/use-versioned-lib/openapi.yaml rename to packages/samples/test/output/use-versioned-lib/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/output/versioning/openapi.v1.yaml b/packages/samples/test/output/versioning/@typespec/openapi3/openapi.v1.yaml similarity index 100% rename from packages/samples/test/output/versioning/openapi.v1.yaml rename to packages/samples/test/output/versioning/@typespec/openapi3/openapi.v1.yaml diff --git a/packages/samples/test/output/versioning/openapi.v2.yaml b/packages/samples/test/output/versioning/@typespec/openapi3/openapi.v2.yaml similarity index 100% rename from packages/samples/test/output/versioning/openapi.v2.yaml rename to packages/samples/test/output/versioning/@typespec/openapi3/openapi.v2.yaml diff --git a/packages/samples/test/output/visibility/openapi.yaml b/packages/samples/test/output/visibility/@typespec/openapi3/openapi.yaml similarity index 100% rename from packages/samples/test/output/visibility/openapi.yaml rename to packages/samples/test/output/visibility/@typespec/openapi3/openapi.yaml diff --git a/packages/samples/test/samples.test.ts b/packages/samples/test/samples.test.ts new file mode 100644 index 000000000..762617063 --- /dev/null +++ b/packages/samples/test/samples.test.ts @@ -0,0 +1,20 @@ +import { resolvePath } from "@typespec/compiler"; +import { fileURLToPath } from "url"; +import { defineSampleSnaphotTests } from "../src/sample-snapshot-testing.js"; + +const excludedSamples = [ + // fails compilation by design to demo language server + "local-typespec", +]; + +const pkgRoot = resolvePath(fileURLToPath(import.meta.url), "../../.."); +const samplesRoot = resolvePath(pkgRoot, "specs"); +const rootOutputDir = resolvePath(pkgRoot, "test/output"); + +describe("TypeSpec Samples", () => { + defineSampleSnaphotTests({ + sampleDir: samplesRoot, + outputDir: rootOutputDir, + exclude: excludedSamples, + }); +}); diff --git a/packages/samples/tsconfig.json b/packages/samples/tsconfig.json index b1b1fa834..cc4a8dc38 100644 --- a/packages/samples/tsconfig.json +++ b/packages/samples/tsconfig.json @@ -2,10 +2,10 @@ "extends": "../tsconfig.json", "references": [{ "path": "../compiler/tsconfig.json" }, { "path": "../rest/tsconfig.json" }], "compilerOptions": { - "types": [], + "types": ["node", "mocha"], "outDir": "dist", "rootDir": ".", "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo" }, - "include": ["rest-metadata-emitter/**/*.ts"] + "include": ["specs/rest-metadata-emitter/**/*.ts", "src/**/*.ts", "test/**/*.ts"] }