@typespec/compiler 0.52.0-dev.9 → 0.52.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 (140) hide show
  1. package/dist/.scripts/build-init-templates.js +11 -1
  2. package/dist/.scripts/build-init-templates.js.map +1 -1
  3. package/dist/manifest.js +2 -2
  4. package/dist/src/core/checker.d.ts.map +1 -1
  5. package/dist/src/core/checker.js +5 -2
  6. package/dist/src/core/checker.js.map +1 -1
  7. package/dist/src/core/index.d.ts +1 -1
  8. package/dist/src/core/index.d.ts.map +1 -1
  9. package/dist/src/core/index.js +1 -1
  10. package/dist/src/core/index.js.map +1 -1
  11. package/dist/src/core/library.d.ts +2 -2
  12. package/dist/src/core/library.d.ts.map +1 -1
  13. package/dist/src/core/library.js +1 -15
  14. package/dist/src/core/library.js.map +1 -1
  15. package/dist/src/core/messages.d.ts +61 -2
  16. package/dist/src/core/messages.d.ts.map +1 -1
  17. package/dist/src/core/messages.js +20 -1
  18. package/dist/src/core/messages.js.map +1 -1
  19. package/dist/src/core/mime-type.d.ts +7 -0
  20. package/dist/src/core/mime-type.d.ts.map +1 -0
  21. package/dist/src/core/mime-type.js +19 -0
  22. package/dist/src/core/mime-type.js.map +1 -0
  23. package/dist/src/core/node-host.d.ts +1 -0
  24. package/dist/src/core/node-host.d.ts.map +1 -1
  25. package/dist/src/core/node-host.js +18 -5
  26. package/dist/src/core/node-host.js.map +1 -1
  27. package/dist/src/core/param-message.d.ts +3 -0
  28. package/dist/src/core/param-message.d.ts.map +1 -0
  29. package/dist/src/core/param-message.js +16 -0
  30. package/dist/src/core/param-message.js.map +1 -0
  31. package/dist/src/core/program.d.ts.map +1 -1
  32. package/dist/src/core/program.js +25 -14
  33. package/dist/src/core/program.js.map +1 -1
  34. package/dist/src/core/util.d.ts +1 -2
  35. package/dist/src/core/util.d.ts.map +1 -1
  36. package/dist/src/core/util.js +2 -3
  37. package/dist/src/core/util.js.map +1 -1
  38. package/dist/src/init/core-templates.d.ts.map +1 -1
  39. package/dist/src/init/core-templates.js +2 -3
  40. package/dist/src/init/core-templates.js.map +1 -1
  41. package/dist/src/init/init.d.ts.map +1 -1
  42. package/dist/src/init/init.js +3 -4
  43. package/dist/src/init/init.js.map +1 -1
  44. package/dist/src/lib/decorators.d.ts +2 -1
  45. package/dist/src/lib/decorators.d.ts.map +1 -1
  46. package/dist/src/lib/decorators.js +1 -0
  47. package/dist/src/lib/decorators.js.map +1 -1
  48. package/dist/src/lib/encoded-names.d.ts +30 -0
  49. package/dist/src/lib/encoded-names.d.ts.map +1 -0
  50. package/dist/src/lib/encoded-names.js +132 -0
  51. package/dist/src/lib/encoded-names.js.map +1 -0
  52. package/dist/src/manifest.d.ts.map +1 -1
  53. package/dist/src/manifest.js +10 -3
  54. package/dist/src/manifest.js.map +1 -1
  55. package/dist/src/server/classify.d.ts +8 -0
  56. package/dist/src/server/classify.d.ts.map +1 -0
  57. package/dist/src/server/classify.js +310 -0
  58. package/dist/src/server/classify.js.map +1 -0
  59. package/dist/src/server/compile-service.d.ts +42 -0
  60. package/dist/src/server/compile-service.d.ts.map +1 -0
  61. package/dist/src/server/compile-service.js +163 -0
  62. package/dist/src/server/compile-service.js.map +1 -0
  63. package/dist/src/server/completion.js +1 -1
  64. package/dist/src/server/completion.js.map +1 -1
  65. package/dist/src/server/constants.d.ts +7 -0
  66. package/dist/src/server/constants.d.ts.map +1 -0
  67. package/dist/src/server/constants.js +13 -0
  68. package/dist/src/server/constants.js.map +1 -0
  69. package/dist/src/server/file-service.d.ts +18 -0
  70. package/dist/src/server/file-service.d.ts.map +1 -0
  71. package/dist/src/server/file-service.js +56 -0
  72. package/dist/src/server/file-service.js.map +1 -0
  73. package/dist/src/server/file-system-cache.d.ts +25 -0
  74. package/dist/src/server/file-system-cache.d.ts.map +1 -0
  75. package/dist/src/server/file-system-cache.js +27 -0
  76. package/dist/src/server/file-system-cache.js.map +1 -0
  77. package/dist/src/server/index.d.ts +2 -1
  78. package/dist/src/server/index.d.ts.map +1 -1
  79. package/dist/src/server/index.js +2 -1
  80. package/dist/src/server/index.js.map +1 -1
  81. package/dist/src/server/server.js.map +1 -1
  82. package/dist/src/server/serverlib.d.ts +1 -71
  83. package/dist/src/server/serverlib.d.ts.map +1 -1
  84. package/dist/src/server/serverlib.js +115 -622
  85. package/dist/src/server/serverlib.js.map +1 -1
  86. package/dist/src/server/types.d.ts +76 -0
  87. package/dist/src/server/types.d.ts.map +1 -0
  88. package/dist/src/server/types.js +26 -0
  89. package/dist/src/server/types.js.map +1 -0
  90. package/dist/src/server/update-manager.d.ts +19 -0
  91. package/dist/src/server/update-manager.d.ts.map +1 -0
  92. package/dist/src/server/update-manager.js +70 -0
  93. package/dist/src/server/update-manager.js.map +1 -0
  94. package/dist/src/testing/test-host.js +2 -2
  95. package/dist/src/testing/test-host.js.map +1 -1
  96. package/dist/src/testing/test-utils.d.ts +2 -0
  97. package/dist/src/testing/test-utils.d.ts.map +1 -1
  98. package/dist/src/testing/test-utils.js +8 -3
  99. package/dist/src/testing/test-utils.js.map +1 -1
  100. package/dist/src/testing/types.d.ts +2 -2
  101. package/dist/src/testing/types.d.ts.map +1 -1
  102. package/lib/decorators.tsp +26 -0
  103. package/package.json +11 -12
  104. package/templates/__snapshots__/emitter-ts/src/testing/index.ts +1 -1
  105. package/templates/__snapshots__/emitter-ts/test/hello.test.ts +1 -1
  106. package/templates/__snapshots__/emitter-ts/test/test-host.ts +2 -2
  107. package/templates/__snapshots__/library-ts/.eslintrc.yml +14 -0
  108. package/templates/__snapshots__/library-ts/lib/decorators.tsp +12 -0
  109. package/templates/__snapshots__/library-ts/lib/main.tsp +1 -0
  110. package/templates/__snapshots__/library-ts/package.json +40 -0
  111. package/templates/__snapshots__/library-ts/prettierrc.yaml +8 -0
  112. package/templates/__snapshots__/library-ts/src/decorators.ts +33 -0
  113. package/templates/__snapshots__/library-ts/src/index.ts +2 -0
  114. package/templates/__snapshots__/library-ts/src/lib.ts +20 -0
  115. package/templates/__snapshots__/library-ts/src/linter.ts +14 -0
  116. package/templates/__snapshots__/library-ts/src/rules/no-interfaces.rule.ts +19 -0
  117. package/templates/{emitter-ts → __snapshots__/library-ts}/src/testing/index.ts +2 -2
  118. package/templates/__snapshots__/library-ts/test/decorators.test.ts +48 -0
  119. package/templates/__snapshots__/library-ts/test/rules/no-interfaces.rule.test.ts +29 -0
  120. package/templates/__snapshots__/library-ts/test/test-host.ts +17 -0
  121. package/templates/__snapshots__/library-ts/tsconfig.json +17 -0
  122. package/templates/emitter-ts/src/testing/index.ts.mu +8 -0
  123. package/templates/emitter-ts/test/hello.test.ts +1 -1
  124. package/templates/emitter-ts/test/test-host.ts.mu +2 -2
  125. package/templates/library-ts/.eslintrc.yml +14 -0
  126. package/templates/library-ts/lib/decorators.tsp.mu +12 -0
  127. package/templates/library-ts/lib/main.tsp +1 -0
  128. package/templates/library-ts/package.json +40 -0
  129. package/templates/library-ts/prettierrc.yaml +8 -0
  130. package/templates/library-ts/src/decorators.ts +33 -0
  131. package/templates/library-ts/src/index.ts +2 -0
  132. package/templates/library-ts/src/lib.ts +20 -0
  133. package/templates/library-ts/src/linter.ts +14 -0
  134. package/templates/library-ts/src/rules/no-interfaces.rule.ts +19 -0
  135. package/templates/library-ts/src/testing/index.ts.mu +8 -0
  136. package/templates/library-ts/test/decorators.test.ts.mu +48 -0
  137. package/templates/library-ts/test/rules/no-interfaces.rule.test.ts +29 -0
  138. package/templates/library-ts/test/test-host.ts.mu +17 -0
  139. package/templates/library-ts/tsconfig.json +17 -0
  140. package/templates/scaffolding.json +80 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typespec/compiler",
3
- "version": "0.52.0-dev.9",
3
+ "version": "0.52.0",
4
4
  "description": "TypeSpec Compiler Preview",
5
5
  "author": "Microsoft Corporation",
6
6
  "license": "MIT",
@@ -73,24 +73,23 @@
73
73
  },
74
74
  "devDependencies": {
75
75
  "@types/babel__code-frame": "~7.0.6",
76
- "@types/mocha": "~10.0.6",
77
76
  "@types/mustache": "~4.2.5",
78
77
  "@types/node": "~18.11.9",
79
78
  "@types/prompts": "~2.4.9",
80
79
  "@types/semver": "^7.5.6",
81
80
  "@types/yargs": "~17.0.32",
82
- "@typespec/eslint-config-typespec": "~0.51.0 || >=0.52.0-dev <0.52.0",
83
- "@typespec/internal-build-utils": "~0.51.0 || >=0.52.0-dev <0.52.0",
81
+ "@typespec/eslint-config-typespec": "~0.52.0",
82
+ "@typespec/internal-build-utils": "~0.52.0",
84
83
  "eslint": "^8.55.0",
85
84
  "grammarkdown": "~3.3.2",
86
- "mocha": "~10.2.0",
87
- "mocha-junit-reporter": "~2.2.1",
88
- "mocha-multi-reporters": "~1.5.1",
85
+ "vitest": "^1.2.0",
86
+ "@vitest/coverage-v8": "^1.1.0",
87
+ "@vitest/ui": "~1.1.3",
89
88
  "c8": "~8.0.1",
90
89
  "prettier-plugin-organize-imports": "~3.2.4",
91
90
  "source-map-support": "~0.5.21",
92
91
  "rimraf": "~5.0.1",
93
- "tmlanguage-generator": "~0.5.1 || >=0.6.0-dev <0.6.0",
92
+ "tmlanguage-generator": "~0.5.2",
94
93
  "typescript": "~5.3.3",
95
94
  "vscode-oniguruma": "~2.0.1",
96
95
  "vscode-textmate": "~9.0.0",
@@ -98,7 +97,6 @@
98
97
  "@types/sinon": "~10.0.20",
99
98
  "ts-node": "~10.9.1"
100
99
  },
101
- "peerDependencies": {},
102
100
  "scripts": {
103
101
  "clean": "rimraf ./dist ./temp",
104
102
  "build:init-templates-index": "node --no-warnings --experimental-specifier-resolution=node --loader ts-node/esm ./.scripts/build-init-templates.ts",
@@ -108,9 +106,10 @@
108
106
  "watch-tmlanguage": "node scripts/watch-tmlanguage.js",
109
107
  "generate-tmlanguage": "node scripts/generate-tmlanguage.js",
110
108
  "dogfood": "node scripts/dogfood.js",
111
- "test": "mocha",
112
- "test-official": "c8 mocha --forbid-only --reporter mocha-multi-reporters",
113
- "e2e": "mocha --config ./.mocharc.e2e.yaml",
109
+ "test": "vitest run",
110
+ "test:ui": "vitest --ui",
111
+ "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism",
112
+ "e2e": "vitest run --config ./vitest.config.e2e.ts",
114
113
  "gen-manifest": "node scripts/generate-manifest.js",
115
114
  "regen-nonascii": "node scripts/regen-nonascii.js",
116
115
  "fuzz": "node dist/test/manual/fuzz.js run",
@@ -2,7 +2,7 @@ import { resolvePath } from "@typespec/compiler";
2
2
  import { createTestLibrary, TypeSpecTestLibrary } from "@typespec/compiler/testing";
3
3
  import { fileURLToPath } from "url";
4
4
 
5
- export const TestLibrary: TypeSpecTestLibrary = createTestLibrary({
5
+ export const EmitterTsTestLibrary: TypeSpecTestLibrary = createTestLibrary({
6
6
  name: "emitter-ts",
7
7
  packageRoot: resolvePath(fileURLToPath(import.meta.url), "../../../../"),
8
8
  });
@@ -1,5 +1,5 @@
1
1
  import { strictEqual } from "node:assert";
2
- import { describe, it } from "node:test";
2
+ import { describe, it } from "vitest";
3
3
  import { emit } from "./test-host.js";
4
4
 
5
5
  describe("hello", () => {
@@ -4,11 +4,11 @@ import {
4
4
  createTestWrapper,
5
5
  expectDiagnosticEmpty,
6
6
  } from "@typespec/compiler/testing";
7
- import { TestLibrary } from "../src/testing/index.js";
7
+ import { EmitterTsTestLibrary } from "../src/testing/index.js";
8
8
 
9
9
  export async function createEmitterTsTestHost() {
10
10
  return createTestHost({
11
- libraries: [TestLibrary],
11
+ libraries: [EmitterTsTestLibrary],
12
12
  });
13
13
  }
14
14
 
@@ -0,0 +1,14 @@
1
+ root: true
2
+ env:
3
+ es2021: true
4
+ node: true
5
+ extends:
6
+ - eslint:recommended
7
+ - plugin:@typescript-eslint/recommended
8
+ parser: "@typescript-eslint/parser"
9
+ parserOptions:
10
+ ecmaVersion: latest
11
+ sourceType: module
12
+ plugins:
13
+ - "@typescript-eslint"
14
+ rules: {}
@@ -0,0 +1,12 @@
1
+ import "../dist/src/decorators.js";
2
+
3
+ using TypeSpec.Reflection;
4
+
5
+ namespace LibraryTs;
6
+
7
+ /**
8
+ * __Example Decorator__
9
+ * Provide an alternate name for an operation.
10
+ * @param name The alternate name.
11
+ */
12
+ extern dec alternateName(target: Operation, name: valueof string);
@@ -0,0 +1 @@
1
+ import "./decorators.tsp";
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "library-ts",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/src/index.js",
6
+ "tspMain": "lib/main.tsp",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/src/index.d.ts",
10
+ "default": "./dist/src/index.js"
11
+ },
12
+ "./testing": {
13
+ "types": "./dist/src/testing/index.d.ts",
14
+ "default": "./dist/src/testing/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "@typespec/compiler": "latest"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "latest",
22
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
23
+ "@typescript-eslint/parser": "^6.0.0",
24
+ "@typespec/library-linter": "latest",
25
+ "eslint": "^8.45.0",
26
+ "prettier": "^3.0.3",
27
+ "typescript": "^5.3.3"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc && npm run build:tsp",
31
+ "watch": "tsc --watch",
32
+ "build:tsp": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit",
33
+ "test": "node --test ./dist/test/",
34
+ "lint": "eslint src/ test/ --report-unused-disable-directives --max-warnings=0",
35
+ "lint:fix": "eslint . --report-unused-disable-directives --fix",
36
+ "format": "prettier . --write",
37
+ "format:check": "prettier --check ."
38
+ },
39
+ "private": true
40
+ }
@@ -0,0 +1,8 @@
1
+ trailingComma: "all"
2
+ printWidth: 120
3
+ quoteProps: "consistent"
4
+ endOfLine: lf
5
+ arrowParens: always
6
+ plugins:
7
+ - "./node_modules/@typespec/prettier-plugin-typespec/dist/index.js"
8
+ overrides: [{ "files": "*.tsp", "options": { "parser": "typespec" } }]
@@ -0,0 +1,33 @@
1
+ import { DecoratorContext, Operation, Program } from "@typespec/compiler";
2
+ import { StateKeys, reportDiagnostic } from "./lib.js";
3
+
4
+ export const namespace = "LibraryTs";
5
+
6
+ /**
7
+ * __Example implementation of the `@alternateName` decorator.__
8
+ *
9
+ * @param context Decorator context.
10
+ * @param target Decorator target. Must be an operation.
11
+ * @param name Alternate name.
12
+ */
13
+ export function $alternateName(context: DecoratorContext, target: Operation, name: string) {
14
+ if (name === "banned") {
15
+ reportDiagnostic(context.program, {
16
+ code: "banned-alternate-name",
17
+ target: context.getArgumentTarget(0)!,
18
+ format: { name },
19
+ });
20
+ }
21
+ context.program.stateMap(StateKeys.alternateName).set(target, name);
22
+ }
23
+
24
+ /**
25
+ * __Example accessor for the `@alternateName` decorator.__
26
+ *
27
+ * @param program TypeSpec program.
28
+ * @param target Decorator target. Must be an operation.
29
+ * @returns Altenate name if provided on the given operation or undefined
30
+ */
31
+ export function getAlternateName(program: Program, target: Operation): string | undefined {
32
+ return program.stateMap(StateKeys.alternateName).get(target);
33
+ }
@@ -0,0 +1,2 @@
1
+ export { getAlternateName } from "./decorators.js";
2
+ export { $lib } from "./lib.js";
@@ -0,0 +1,20 @@
1
+ import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler";
2
+
3
+ export const $lib = createTypeSpecLibrary({
4
+ name: "library-ts",
5
+ // Define diagnostics for the library. This will provide a typed API to report diagnostic as well as a auto doc generation.
6
+ diagnostics: {
7
+ "banned-alternate-name": {
8
+ severity: "error",
9
+ messages: {
10
+ default: paramMessage`Banned alternate name "${"name"}".`,
11
+ },
12
+ },
13
+ },
14
+ // Defined state keys for storing metadata in decorator.
15
+ state: {
16
+ alternateName: { description: "alternateName" },
17
+ },
18
+ });
19
+
20
+ export const { reportDiagnostic, createDiagnostic, stateKeys: StateKeys } = $lib;
@@ -0,0 +1,14 @@
1
+ import { defineLinter } from "@typespec/compiler";
2
+ import { noInterfaceRule } from "./rules/no-interfaces.rule.js";
3
+
4
+ export const $linter = defineLinter({
5
+ rules: [noInterfaceRule],
6
+ ruleSets: {
7
+ recommended: {
8
+ enable: { [`library-ts/${noInterfaceRule.name}`]: true },
9
+ },
10
+ all: {
11
+ enable: { [`library-ts/${noInterfaceRule.name}`]: true },
12
+ },
13
+ },
14
+ });
@@ -0,0 +1,19 @@
1
+ import { createRule } from "@typespec/compiler";
2
+
3
+ export const noInterfaceRule = createRule({
4
+ name: "no-interface",
5
+ severity: "warning",
6
+ description: "Make sure interface are not used.",
7
+ messages: {
8
+ default: "Interface shouldn't be used with this library. Keep operations at the root.",
9
+ },
10
+ create: (context) => {
11
+ return {
12
+ interface: (iface) => {
13
+ context.reportDiagnostic({
14
+ target: iface,
15
+ });
16
+ },
17
+ };
18
+ },
19
+ });
@@ -2,7 +2,7 @@ import { resolvePath } from "@typespec/compiler";
2
2
  import { createTestLibrary, TypeSpecTestLibrary } from "@typespec/compiler/testing";
3
3
  import { fileURLToPath } from "url";
4
4
 
5
- export const TestLibrary: TypeSpecTestLibrary = createTestLibrary({
6
- name: "{{name}}",
5
+ export const LibraryTsTestLibrary: TypeSpecTestLibrary = createTestLibrary({
6
+ name: "library-ts",
7
7
  packageRoot: resolvePath(fileURLToPath(import.meta.url), "../../../../"),
8
8
  });
@@ -0,0 +1,48 @@
1
+ import { strictEqual } from "node:assert";
2
+ import { describe, it, beforeEach } from "node:test";
3
+ import { Operation } from "@typespec/compiler";
4
+ import { BasicTestRunner, expectDiagnostics, extractCursor } from "@typespec/compiler/testing";
5
+ import { getAlternateName } from "../src/decorators.js";
6
+ import { createLibraryTsTestRunner } from "./test-host.js";
7
+
8
+ describe("decorators", () => {
9
+ let runner: BasicTestRunner;
10
+
11
+ beforeEach(async () => {
12
+ runner = await createLibraryTsTestRunner();
13
+ })
14
+
15
+ describe("@alternateName", () => {
16
+ it("set alternate name on operation", async () => {
17
+ const { test } = (await runner.compile(
18
+ `@alternateName("bar") @test op test(): void;`
19
+ )) as { test: Operation };
20
+ strictEqual(getAlternateName(runner.program, test), "bar");
21
+ });
22
+
23
+ it("emit diagnostic if not used on an operation", async () => {
24
+ const diagnostics = await runner.diagnose(
25
+ `@alternateName("bar") model Test {}`
26
+ );
27
+ expectDiagnostics(diagnostics, {
28
+ severity: "error",
29
+ code: "decorator-wrong-target",
30
+ message: "Cannot apply @alternateName decorator to Test since it is not assignable to Operation"
31
+ })
32
+ });
33
+
34
+
35
+ it("emit diagnostic if using banned name", async () => {
36
+ const {pos, source} = extractCursor(`@alternateName(┆"banned") op test(): void;`)
37
+ const diagnostics = await runner.diagnose(
38
+ source
39
+ );
40
+ expectDiagnostics(diagnostics, {
41
+ severity: "error",
42
+ code: "library-ts/banned-alternate-name",
43
+ message: `Banned alternate name "banned".`,
44
+ pos: pos + runner.autoCodeOffset
45
+ })
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,29 @@
1
+ import {
2
+ LinterRuleTester,
3
+ createLinterRuleTester,
4
+ createTestRunner,
5
+ } from "@typespec/compiler/testing";
6
+ import { beforeEach, describe, it } from "node:test";
7
+ import { noInterfaceRule } from "../../src/rules/no-interfaces.rule.js";
8
+
9
+ describe("noInterfaceRule", () => {
10
+ let ruleTester: LinterRuleTester;
11
+
12
+ beforeEach(async () => {
13
+ const runner = await createTestRunner();
14
+ ruleTester = createLinterRuleTester(runner, noInterfaceRule, "library-ts");
15
+ });
16
+
17
+ describe("models", () => {
18
+ it("emit diagnostics if using interfaces", async () => {
19
+ await ruleTester.expect(`interface Test {}`).toEmitDiagnostics({
20
+ code: "library-ts/no-interface",
21
+ message: "Interface shouldn't be used with this library. Keep operations at the root.",
22
+ });
23
+ });
24
+
25
+ it("should be valid if operation is at the root", async () => {
26
+ await ruleTester.expect(`op test(): void;`).toBeValid();
27
+ });
28
+ });
29
+ });
@@ -0,0 +1,17 @@
1
+ import { createTestHost, createTestWrapper } from "@typespec/compiler/testing";
2
+ import { LibraryTsTestLibrary } from "../src/testing/index.js";
3
+
4
+ export async function createLibraryTsTestHost() {
5
+ return createTestHost({
6
+ libraries: [LibraryTsTestLibrary],
7
+ });
8
+ }
9
+
10
+ export async function createLibraryTsTestRunner() {
11
+ const host = await createLibraryTsTestHost();
12
+
13
+ return createTestWrapper(host, {
14
+ autoUsings: ["LibraryTs"]
15
+ });
16
+ }
17
+
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "useDefineForClassFields": true,
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "lib": ["ES2022"],
8
+ "rootDir": ".",
9
+ "outDir": "dist",
10
+ "sourceMap": true,
11
+ "declaration": true,
12
+
13
+ /* Linting */
14
+ "strict": true
15
+ },
16
+ "include": ["src", "test"]
17
+ }
@@ -0,0 +1,8 @@
1
+ import { resolvePath } from "@typespec/compiler";
2
+ import { createTestLibrary, TypeSpecTestLibrary } from "@typespec/compiler/testing";
3
+ import { fileURLToPath } from "url";
4
+
5
+ export const {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary: TypeSpecTestLibrary = createTestLibrary({
6
+ name: "{{name}}",
7
+ packageRoot: resolvePath(fileURLToPath(import.meta.url), "../../../../"),
8
+ });
@@ -1,5 +1,5 @@
1
1
  import { strictEqual } from "node:assert";
2
- import { describe, it } from "node:test";
2
+ import { describe, it } from "vitest";
3
3
  import { emit } from "./test-host.js";
4
4
 
5
5
  describe("hello", () => {
@@ -4,11 +4,11 @@ import {
4
4
  createTestWrapper,
5
5
  expectDiagnosticEmpty,
6
6
  } from "@typespec/compiler/testing";
7
- import { TestLibrary } from "../src/testing/index.js";
7
+ import { {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary } from "../src/testing/index.js";
8
8
 
9
9
  export async function create{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestHost() {
10
10
  return createTestHost({
11
- libraries: [TestLibrary],
11
+ libraries: [{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary],
12
12
  });
13
13
  }
14
14
 
@@ -0,0 +1,14 @@
1
+ root: true
2
+ env:
3
+ es2021: true
4
+ node: true
5
+ extends:
6
+ - eslint:recommended
7
+ - plugin:@typescript-eslint/recommended
8
+ parser: "@typescript-eslint/parser"
9
+ parserOptions:
10
+ ecmaVersion: latest
11
+ sourceType: module
12
+ plugins:
13
+ - "@typescript-eslint"
14
+ rules: {}
@@ -0,0 +1,12 @@
1
+ import "../dist/src/decorators.js";
2
+
3
+ using TypeSpec.Reflection;
4
+
5
+ namespace {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}};
6
+
7
+ /**
8
+ * __Example Decorator__
9
+ * Provide an alternate name for an operation.
10
+ * @param name The alternate name.
11
+ */
12
+ extern dec alternateName(target: Operation, name: valueof string);
@@ -0,0 +1 @@
1
+ import "./decorators.tsp";
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/src/index.js",
6
+ "tspMain": "lib/main.tsp",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/src/index.d.ts",
10
+ "default": "./dist/src/index.js"
11
+ },
12
+ "./testing": {
13
+ "types": "./dist/src/testing/index.d.ts",
14
+ "default": "./dist/src/testing/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "@typespec/compiler": "latest"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "latest",
22
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
23
+ "@typescript-eslint/parser": "^6.0.0",
24
+ "@typespec/library-linter": "latest",
25
+ "eslint": "^8.45.0",
26
+ "prettier": "^3.0.3",
27
+ "typescript": "^5.3.3"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc && npm run build:tsp",
31
+ "watch": "tsc --watch",
32
+ "build:tsp": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit",
33
+ "test": "node --test ./dist/test/",
34
+ "lint": "eslint src/ test/ --report-unused-disable-directives --max-warnings=0",
35
+ "lint:fix": "eslint . --report-unused-disable-directives --fix",
36
+ "format": "prettier . --write",
37
+ "format:check": "prettier --check ."
38
+ },
39
+ "private": true
40
+ }
@@ -0,0 +1,8 @@
1
+ trailingComma: "all"
2
+ printWidth: 120
3
+ quoteProps: "consistent"
4
+ endOfLine: lf
5
+ arrowParens: always
6
+ plugins:
7
+ - "./node_modules/@typespec/prettier-plugin-typespec/dist/index.js"
8
+ overrides: [{ "files": "*.tsp", "options": { "parser": "typespec" } }]
@@ -0,0 +1,33 @@
1
+ import { DecoratorContext, Operation, Program } from "@typespec/compiler";
2
+ import { StateKeys, reportDiagnostic } from "./lib.js";
3
+
4
+ export const namespace = "{{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}";
5
+
6
+ /**
7
+ * __Example implementation of the `@alternateName` decorator.__
8
+ *
9
+ * @param context Decorator context.
10
+ * @param target Decorator target. Must be an operation.
11
+ * @param name Alternate name.
12
+ */
13
+ export function $alternateName(context: DecoratorContext, target: Operation, name: string) {
14
+ if (name === "banned") {
15
+ reportDiagnostic(context.program, {
16
+ code: "banned-alternate-name",
17
+ target: context.getArgumentTarget(0)!,
18
+ format: { name },
19
+ });
20
+ }
21
+ context.program.stateMap(StateKeys.alternateName).set(target, name);
22
+ }
23
+
24
+ /**
25
+ * __Example accessor for the `@alternateName` decorator.__
26
+ *
27
+ * @param program TypeSpec program.
28
+ * @param target Decorator target. Must be an operation.
29
+ * @returns Altenate name if provided on the given operation or undefined
30
+ */
31
+ export function getAlternateName(program: Program, target: Operation): string | undefined {
32
+ return program.stateMap(StateKeys.alternateName).get(target);
33
+ }
@@ -0,0 +1,2 @@
1
+ export { getAlternateName } from "./decorators.js";
2
+ export { $lib } from "./lib.js";
@@ -0,0 +1,20 @@
1
+ import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler";
2
+
3
+ export const $lib = createTypeSpecLibrary({
4
+ name: "{{name}}",
5
+ // Define diagnostics for the library. This will provide a typed API to report diagnostic as well as a auto doc generation.
6
+ diagnostics: {
7
+ "banned-alternate-name": {
8
+ severity: "error",
9
+ messages: {
10
+ default: paramMessage`Banned alternate name "${"name"}".`,
11
+ },
12
+ },
13
+ },
14
+ // Defined state keys for storing metadata in decorator.
15
+ state: {
16
+ alternateName: { description: "alternateName" },
17
+ },
18
+ });
19
+
20
+ export const { reportDiagnostic, createDiagnostic, stateKeys: StateKeys } = $lib;
@@ -0,0 +1,14 @@
1
+ import { defineLinter } from "@typespec/compiler";
2
+ import { noInterfaceRule } from "./rules/no-interfaces.rule.js";
3
+
4
+ export const $linter = defineLinter({
5
+ rules: [noInterfaceRule],
6
+ ruleSets: {
7
+ recommended: {
8
+ enable: { [`{{name}}/${noInterfaceRule.name}`]: true },
9
+ },
10
+ all: {
11
+ enable: { [`{{name}}/${noInterfaceRule.name}`]: true },
12
+ },
13
+ },
14
+ });
@@ -0,0 +1,19 @@
1
+ import { createRule } from "@typespec/compiler";
2
+
3
+ export const noInterfaceRule = createRule({
4
+ name: "no-interface",
5
+ severity: "warning",
6
+ description: "Make sure interface are not used.",
7
+ messages: {
8
+ default: "Interface shouldn't be used with this library. Keep operations at the root.",
9
+ },
10
+ create: (context) => {
11
+ return {
12
+ interface: (iface) => {
13
+ context.reportDiagnostic({
14
+ target: iface,
15
+ });
16
+ },
17
+ };
18
+ },
19
+ });
@@ -0,0 +1,8 @@
1
+ import { resolvePath } from "@typespec/compiler";
2
+ import { createTestLibrary, TypeSpecTestLibrary } from "@typespec/compiler/testing";
3
+ import { fileURLToPath } from "url";
4
+
5
+ export const {{#casing.pascalCase}}{{name}}{{/casing.pascalCase}}TestLibrary: TypeSpecTestLibrary = createTestLibrary({
6
+ name: "{{name}}",
7
+ packageRoot: resolvePath(fileURLToPath(import.meta.url), "../../../../"),
8
+ });