@typespec/emitter-framework 0.9.0-dev.8 → 0.10.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/testing/scenario-test/code-block-expectation.d.ts +33 -0
  3. package/dist/src/testing/scenario-test/code-block-expectation.d.ts.map +1 -0
  4. package/dist/src/testing/scenario-test/code-block-expectation.js +69 -0
  5. package/dist/src/testing/scenario-test/code-block-expectation.test.d.ts +2 -0
  6. package/dist/src/testing/scenario-test/code-block-expectation.test.d.ts.map +1 -0
  7. package/dist/src/testing/scenario-test/code-block-expectation.test.js +80 -0
  8. package/dist/src/testing/scenario-test/harness.d.ts +2 -2
  9. package/dist/src/testing/scenario-test/harness.d.ts.map +1 -1
  10. package/dist/src/testing/scenario-test/harness.js +69 -158
  11. package/dist/src/testing/scenario-test/index.d.ts +0 -1
  12. package/dist/src/testing/scenario-test/index.d.ts.map +1 -1
  13. package/dist/src/testing/scenario-test/index.js +1 -2
  14. package/dist/src/testing/scenario-test/snippet-extractor.d.ts +1 -1
  15. package/dist/src/testing/scenario-test/snippet-extractor.js +1 -1
  16. package/dist/test/testing/snippet-extractor-csharp.test.js +3 -3
  17. package/dist/test/testing/snippet-extractor-java.test.js +3 -3
  18. package/dist/test/testing/snippet-extractor-python.test.js +2 -2
  19. package/dist/test/testing/snippet-extractor-typescript.test.js +3 -3
  20. package/package.json +20 -12
  21. package/src/testing/scenario-test/code-block-expectation.test.ts +95 -0
  22. package/src/testing/scenario-test/code-block-expectation.ts +115 -0
  23. package/src/testing/scenario-test/harness.ts +91 -236
  24. package/src/testing/scenario-test/index.ts +0 -1
  25. package/src/testing/scenario-test/snippet-extractor.ts +1 -1
  26. package/test/testing/snippet-extractor-csharp.test.ts +3 -3
  27. package/test/testing/snippet-extractor-java.test.ts +3 -3
  28. package/test/testing/snippet-extractor-python.test.ts +2 -2
  29. package/test/testing/snippet-extractor-typescript.test.ts +3 -3
  30. package/dist/src/testing/scenario-test/test-host.d.ts +0 -8
  31. package/dist/src/testing/scenario-test/test-host.d.ts.map +0 -1
  32. package/dist/src/testing/scenario-test/test-host.js +0 -49
  33. package/src/testing/scenario-test/test-host.ts +0 -83
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/emitter-framework",
3
- "version": "0.9.0-dev.8",
3
+ "version": "0.10.0-dev.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "repository": {
@@ -23,9 +23,18 @@
23
23
  },
24
24
  "imports": {
25
25
  "#test/*": "./test/*",
26
- "#core/*": "./src/core/*",
27
- "#csharp/*": "./src/csharp/*",
28
- "#typescript/*": "./src/typescript/*"
26
+ "#core/*": {
27
+ "development": "./src/core/*",
28
+ "default": "./dist/src/core/*"
29
+ },
30
+ "#csharp/*": {
31
+ "development": "./src/csharp/*",
32
+ "default": "./dist/src/csharp/*"
33
+ },
34
+ "#typescript/*": {
35
+ "development": "./src/typescript/*",
36
+ "default": "./dist/src/typescript/*"
37
+ }
29
38
  },
30
39
  "keywords": [],
31
40
  "author": "",
@@ -35,21 +44,20 @@
35
44
  "@alloy-js/core": "^0.18.2",
36
45
  "@alloy-js/typescript": "^0.18.0",
37
46
  "@alloy-js/csharp": "^0.18.0",
38
- "@typespec/compiler": "^1.1.0",
39
- "@typespec/http": "^1.1.0",
40
- "@typespec/rest": "^0.71.0 || >=0.72.0-dev <0.72.0"
47
+ "@typespec/compiler": "^1.2.0",
48
+ "@typespec/http": "^1.2.0",
49
+ "@typespec/rest": "^0.72.0 || >=0.73.0-dev <0.73.0"
41
50
  },
42
51
  "devDependencies": {
43
52
  "@alloy-js/cli": "^0.18.0",
44
53
  "@alloy-js/rollup-plugin": "^0.1.0",
45
54
  "@alloy-js/core": "^0.18.2",
46
55
  "@alloy-js/typescript": "^0.18.0",
47
- "@types/minimist": "^1.2.5",
48
- "@typespec/compiler": "^1.1.0",
49
- "@typespec/http": "^1.1.0",
50
- "@typespec/rest": "^0.71.0 || >=0.72.0-dev <0.72.0",
56
+ "@typespec/compiler": "^1.2.0",
57
+ "@typespec/http": "^1.2.0",
58
+ "@typespec/rest": "^0.72.0 || >=0.73.0-dev <0.73.0",
51
59
  "concurrently": "^9.1.2",
52
- "minimist": "^1.2.8",
60
+ "pathe": "^2.0.3",
53
61
  "prettier": "~3.5.3",
54
62
  "web-tree-sitter": "^0.25.4",
55
63
  "tree-sitter-c-sharp": "^0.23.0",
@@ -0,0 +1,95 @@
1
+ import { d } from "@alloy-js/core/testing";
2
+ import { beforeAll, describe, expect, it } from "vitest";
3
+ import { getExcerptForQuery, parseCodeBlockHeading } from "./code-block-expectation.js";
4
+ import {
5
+ createSnippetExtractor,
6
+ createTypeScriptExtractorConfig,
7
+ type SnippetExtractor,
8
+ } from "./snippet-extractor.js";
9
+
10
+ describe("parseCodeBlockHeading", () => {
11
+ it("parse whole file expectation", () => {
12
+ expect(parseCodeBlockHeading("ts path/to/file.ts")).toEqual({
13
+ lang: "ts",
14
+ file: "path/to/file.ts",
15
+ });
16
+ });
17
+
18
+ it("throws error when no file is provided", () => {
19
+ expect(() => parseCodeBlockHeading("ts")).toThrow(
20
+ 'Invalid code block heading: "ts". Missing file path. Expected format: "<lang> <path>"',
21
+ );
22
+ });
23
+
24
+ it("parse parse with type and name", () => {
25
+ expect(parseCodeBlockHeading("ts path/to/file.ts interface foo")).toEqual({
26
+ lang: "ts",
27
+ file: "path/to/file.ts",
28
+ query: {
29
+ type: "interface",
30
+ name: "foo",
31
+ },
32
+ });
33
+ });
34
+
35
+ it("throws error when using type but no name is provided", () => {
36
+ expect(() => parseCodeBlockHeading("ts path/to/file.ts interface")).toThrow(
37
+ 'Invalid code block heading: "ts path/to/file.ts interface". Missing name when using type. Expected format: "<lang> <path> [type] [name]"',
38
+ );
39
+ });
40
+ });
41
+
42
+ describe("getExcerptForQuery", () => {
43
+ let snippetExtractor: SnippetExtractor;
44
+ beforeAll(async () => {
45
+ const tsExtractorConfig = await createTypeScriptExtractorConfig();
46
+ snippetExtractor = createSnippetExtractor(tsExtractorConfig);
47
+ });
48
+
49
+ it("gets a whole file", async () => {
50
+ const expectation = {
51
+ lang: "ts",
52
+ file: "file.ts",
53
+ };
54
+ const outputs = {
55
+ "file.ts": d`
56
+ interface bar {
57
+
58
+ }
59
+ interface foo {
60
+ bar: string;
61
+ }
62
+ `,
63
+ };
64
+ const excerpt = getExcerptForQuery(snippetExtractor, expectation, outputs);
65
+ expect(excerpt).toBe(outputs["file.ts"]);
66
+ });
67
+
68
+ it("gets an interface for typescript", async () => {
69
+ const expectation = {
70
+ lang: "ts",
71
+ file: "file.ts",
72
+ query: {
73
+ type: "interface",
74
+ name: "foo",
75
+ },
76
+ };
77
+ const outputs = {
78
+ "file.ts": d`
79
+ interface bar {
80
+
81
+ }
82
+
83
+ interface foo {
84
+ bar: string;
85
+ }
86
+ `,
87
+ };
88
+ const excerpt = getExcerptForQuery(snippetExtractor, expectation, outputs);
89
+ expect(excerpt).toBe(d`
90
+ interface foo {
91
+ bar: string;
92
+ }
93
+ `);
94
+ });
95
+ });
@@ -0,0 +1,115 @@
1
+ import type { SnippetExtractor } from "./snippet-extractor.js";
2
+
3
+ export interface ElementQuery {
4
+ /** Type to query */
5
+ type: string;
6
+
7
+ /** Name of the type to query */
8
+ name: string;
9
+ }
10
+
11
+ export interface CodeBlockQuery {
12
+ /** Language */
13
+ lang: string;
14
+
15
+ /** File path */
16
+ file: string;
17
+
18
+ /** Query for content in the file */
19
+ query?: ElementQuery;
20
+ }
21
+
22
+ export interface CodeBlockExpectation extends CodeBlockQuery {
23
+ /** Expected content of the code block */
24
+ expected: string;
25
+ }
26
+
27
+ /**
28
+ * Parse a markdown code block following the expectation syntax
29
+ */
30
+ export function parseCodeblockExpectation(heading: string, content: string): CodeBlockExpectation {
31
+ const query = parseCodeBlockHeading(heading);
32
+ return {
33
+ ...query,
34
+ expected: content,
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Parse the codeblock heading for what it should validate.
40
+ * Expected format
41
+ * ```
42
+ * ts path/to/file.ts {type} {name}
43
+ * ```
44
+ */
45
+ export function parseCodeBlockHeading(heading: string): CodeBlockQuery {
46
+ const [lang, file, type, name] = heading.split(" ");
47
+ if (!file) {
48
+ throw new Error(
49
+ `Invalid code block heading: "${heading}". Missing file path. Expected format: "<lang> <path>"`,
50
+ );
51
+ }
52
+
53
+ if (type && !name) {
54
+ throw new Error(
55
+ `Invalid code block heading: "${heading}". Missing name when using type. Expected format: "<lang> <path> [type] [name]"`,
56
+ );
57
+ }
58
+
59
+ return { lang, file, query: type ? { type, name } : undefined };
60
+ }
61
+
62
+ export function getExcerptForQuery(
63
+ snippetExtractor: SnippetExtractor,
64
+ expectation: CodeBlockQuery,
65
+ outputs: Record<string, string>,
66
+ ): string {
67
+ const content = outputs[expectation.file];
68
+
69
+ if (!content) {
70
+ throw new Error(
71
+ `File ${expectation.file} not found in emitted files:\n ${Object.keys(outputs).join("\n")}`,
72
+ );
73
+ }
74
+
75
+ return getExcerptInFile(snippetExtractor, expectation, content);
76
+ }
77
+
78
+ function getExcerptInFile(
79
+ snippetExtractor: SnippetExtractor,
80
+ expectation: CodeBlockQuery,
81
+ sourceFile: string,
82
+ ): string {
83
+ if (expectation.query) {
84
+ const excerpt = tryGetExcerptInFile(snippetExtractor, expectation.query, sourceFile);
85
+ if (!excerpt) {
86
+ throw new Error(
87
+ `Could not find ${expectation.query.type} "${expectation.query.name}" in file "${expectation.file}".`,
88
+ );
89
+ }
90
+ return excerpt;
91
+ } else {
92
+ return sourceFile;
93
+ }
94
+ }
95
+
96
+ function tryGetExcerptInFile(
97
+ snippetExtractor: SnippetExtractor,
98
+ query: ElementQuery,
99
+ sourceFile: string,
100
+ ): string | null {
101
+ switch (query.type) {
102
+ case "interface":
103
+ return snippetExtractor.getInterface(sourceFile, query.name);
104
+ case "type":
105
+ return snippetExtractor.getTypeAlias(sourceFile, query.name);
106
+ case "enum":
107
+ return snippetExtractor.getEnum(sourceFile, query.name);
108
+ case "function":
109
+ return snippetExtractor.getFunction(sourceFile, query.name);
110
+ case "class":
111
+ return snippetExtractor.getClass(sourceFile, query.name);
112
+ default:
113
+ throw new Error("Unsupported type in code block expectation: " + query.type);
114
+ }
115
+ }