@typespec/compiler 0.52.0-dev.9 → 0.53.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.
- package/dist/.scripts/build-init-templates.js +11 -1
- package/dist/.scripts/build-init-templates.js.map +1 -1
- package/dist/manifest.js +2 -2
- package/dist/src/core/checker.d.ts.map +1 -1
- package/dist/src/core/checker.js +5 -2
- package/dist/src/core/checker.js.map +1 -1
- package/dist/src/core/index.d.ts +1 -1
- package/dist/src/core/index.d.ts.map +1 -1
- package/dist/src/core/index.js +1 -1
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/core/library.d.ts +2 -2
- package/dist/src/core/library.d.ts.map +1 -1
- package/dist/src/core/library.js +1 -15
- package/dist/src/core/library.js.map +1 -1
- package/dist/src/core/messages.d.ts +61 -2
- package/dist/src/core/messages.d.ts.map +1 -1
- package/dist/src/core/messages.js +20 -1
- package/dist/src/core/messages.js.map +1 -1
- package/dist/src/core/mime-type.d.ts +7 -0
- package/dist/src/core/mime-type.d.ts.map +1 -0
- package/dist/src/core/mime-type.js +19 -0
- package/dist/src/core/mime-type.js.map +1 -0
- package/dist/src/core/node-host.d.ts +1 -0
- package/dist/src/core/node-host.d.ts.map +1 -1
- package/dist/src/core/node-host.js +18 -5
- package/dist/src/core/node-host.js.map +1 -1
- package/dist/src/core/param-message.d.ts +3 -0
- package/dist/src/core/param-message.d.ts.map +1 -0
- package/dist/src/core/param-message.js +16 -0
- package/dist/src/core/param-message.js.map +1 -0
- package/dist/src/core/program.d.ts.map +1 -1
- package/dist/src/core/program.js +25 -14
- package/dist/src/core/program.js.map +1 -1
- package/dist/src/core/util.d.ts +1 -2
- package/dist/src/core/util.d.ts.map +1 -1
- package/dist/src/core/util.js +2 -3
- package/dist/src/core/util.js.map +1 -1
- package/dist/src/init/core-templates.d.ts.map +1 -1
- package/dist/src/init/core-templates.js +2 -3
- package/dist/src/init/core-templates.js.map +1 -1
- package/dist/src/init/init.d.ts.map +1 -1
- package/dist/src/init/init.js +3 -4
- package/dist/src/init/init.js.map +1 -1
- package/dist/src/lib/decorators.d.ts +2 -1
- package/dist/src/lib/decorators.d.ts.map +1 -1
- package/dist/src/lib/decorators.js +1 -0
- package/dist/src/lib/decorators.js.map +1 -1
- package/dist/src/lib/encoded-names.d.ts +30 -0
- package/dist/src/lib/encoded-names.d.ts.map +1 -0
- package/dist/src/lib/encoded-names.js +132 -0
- package/dist/src/lib/encoded-names.js.map +1 -0
- package/dist/src/manifest.d.ts.map +1 -1
- package/dist/src/manifest.js +10 -3
- package/dist/src/manifest.js.map +1 -1
- package/dist/src/server/classify.d.ts +8 -0
- package/dist/src/server/classify.d.ts.map +1 -0
- package/dist/src/server/classify.js +310 -0
- package/dist/src/server/classify.js.map +1 -0
- package/dist/src/server/compile-service.d.ts +42 -0
- package/dist/src/server/compile-service.d.ts.map +1 -0
- package/dist/src/server/compile-service.js +163 -0
- package/dist/src/server/compile-service.js.map +1 -0
- package/dist/src/server/completion.js +1 -1
- package/dist/src/server/completion.js.map +1 -1
- package/dist/src/server/constants.d.ts +7 -0
- package/dist/src/server/constants.d.ts.map +1 -0
- package/dist/src/server/constants.js +13 -0
- package/dist/src/server/constants.js.map +1 -0
- package/dist/src/server/file-service.d.ts +18 -0
- package/dist/src/server/file-service.d.ts.map +1 -0
- package/dist/src/server/file-service.js +56 -0
- package/dist/src/server/file-service.js.map +1 -0
- package/dist/src/server/file-system-cache.d.ts +25 -0
- package/dist/src/server/file-system-cache.d.ts.map +1 -0
- package/dist/src/server/file-system-cache.js +27 -0
- package/dist/src/server/file-system-cache.js.map +1 -0
- package/dist/src/server/index.d.ts +2 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +2 -1
- package/dist/src/server/index.js.map +1 -1
- package/dist/src/server/server.js.map +1 -1
- package/dist/src/server/serverlib.d.ts +1 -71
- package/dist/src/server/serverlib.d.ts.map +1 -1
- package/dist/src/server/serverlib.js +115 -622
- package/dist/src/server/serverlib.js.map +1 -1
- package/dist/src/server/types.d.ts +76 -0
- package/dist/src/server/types.d.ts.map +1 -0
- package/dist/src/server/types.js +26 -0
- package/dist/src/server/types.js.map +1 -0
- package/dist/src/server/update-manager.d.ts +19 -0
- package/dist/src/server/update-manager.d.ts.map +1 -0
- package/dist/src/server/update-manager.js +70 -0
- package/dist/src/server/update-manager.js.map +1 -0
- package/dist/src/testing/test-host.js +2 -2
- package/dist/src/testing/test-host.js.map +1 -1
- package/dist/src/testing/test-utils.d.ts +2 -0
- package/dist/src/testing/test-utils.d.ts.map +1 -1
- package/dist/src/testing/test-utils.js +8 -3
- package/dist/src/testing/test-utils.js.map +1 -1
- package/dist/src/testing/types.d.ts +2 -2
- package/dist/src/testing/types.d.ts.map +1 -1
- package/lib/decorators.tsp +26 -0
- package/package.json +11 -11
- package/templates/__snapshots__/emitter-ts/src/testing/index.ts +1 -1
- package/templates/__snapshots__/emitter-ts/test/hello.test.ts +1 -1
- package/templates/__snapshots__/emitter-ts/test/test-host.ts +2 -2
- package/templates/__snapshots__/library-ts/.eslintrc.yml +14 -0
- package/templates/__snapshots__/library-ts/lib/decorators.tsp +12 -0
- package/templates/__snapshots__/library-ts/lib/main.tsp +1 -0
- package/templates/__snapshots__/library-ts/package.json +40 -0
- package/templates/__snapshots__/library-ts/prettierrc.yaml +8 -0
- package/templates/__snapshots__/library-ts/src/decorators.ts +33 -0
- package/templates/__snapshots__/library-ts/src/index.ts +2 -0
- package/templates/__snapshots__/library-ts/src/lib.ts +20 -0
- package/templates/__snapshots__/library-ts/src/linter.ts +14 -0
- package/templates/__snapshots__/library-ts/src/rules/no-interfaces.rule.ts +19 -0
- package/templates/{emitter-ts → __snapshots__/library-ts}/src/testing/index.ts +2 -2
- package/templates/__snapshots__/library-ts/test/decorators.test.ts +48 -0
- package/templates/__snapshots__/library-ts/test/rules/no-interfaces.rule.test.ts +29 -0
- package/templates/__snapshots__/library-ts/test/test-host.ts +17 -0
- package/templates/__snapshots__/library-ts/tsconfig.json +17 -0
- package/templates/emitter-ts/src/testing/index.ts.mu +8 -0
- package/templates/emitter-ts/test/hello.test.ts +1 -1
- package/templates/emitter-ts/test/test-host.ts.mu +2 -2
- package/templates/library-ts/.eslintrc.yml +14 -0
- package/templates/library-ts/lib/decorators.tsp.mu +12 -0
- package/templates/library-ts/lib/main.tsp +1 -0
- package/templates/library-ts/package.json +40 -0
- package/templates/library-ts/prettierrc.yaml +8 -0
- package/templates/library-ts/src/decorators.ts +33 -0
- package/templates/library-ts/src/index.ts +2 -0
- package/templates/library-ts/src/lib.ts +20 -0
- package/templates/library-ts/src/linter.ts +14 -0
- package/templates/library-ts/src/rules/no-interfaces.rule.ts +19 -0
- package/templates/library-ts/src/testing/index.ts.mu +8 -0
- package/templates/library-ts/test/decorators.test.ts.mu +48 -0
- package/templates/library-ts/test/rules/no-interfaces.rule.test.ts +29 -0
- package/templates/library-ts/test/test-host.ts.mu +17 -0
- package/templates/library-ts/tsconfig.json +17 -0
- package/templates/scaffolding.json +80 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typespec/compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.0-dev.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.
|
|
83
|
-
"@typespec/internal-build-utils": "~0.
|
|
81
|
+
"@typespec/eslint-config-typespec": "~0.52.0 || >=0.53.0-dev <0.53.0",
|
|
82
|
+
"@typespec/internal-build-utils": "~0.52.0 || >=0.53.0-dev <0.53.0",
|
|
84
83
|
"eslint": "^8.55.0",
|
|
85
84
|
"grammarkdown": "~3.3.2",
|
|
86
|
-
"
|
|
87
|
-
"
|
|
88
|
-
"
|
|
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.
|
|
92
|
+
"tmlanguage-generator": "~0.5.2 || >=0.6.0-dev <0.6.0",
|
|
94
93
|
"typescript": "~5.3.3",
|
|
95
94
|
"vscode-oniguruma": "~2.0.1",
|
|
96
95
|
"vscode-textmate": "~9.0.0",
|
|
@@ -108,9 +107,10 @@
|
|
|
108
107
|
"watch-tmlanguage": "node scripts/watch-tmlanguage.js",
|
|
109
108
|
"generate-tmlanguage": "node scripts/generate-tmlanguage.js",
|
|
110
109
|
"dogfood": "node scripts/dogfood.js",
|
|
111
|
-
"test": "
|
|
112
|
-
"test
|
|
113
|
-
"
|
|
110
|
+
"test": "vitest run",
|
|
111
|
+
"test:ui": "vitest --ui",
|
|
112
|
+
"test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism",
|
|
113
|
+
"e2e": "vitest run --config ./vitest.config.e2e.ts",
|
|
114
114
|
"gen-manifest": "node scripts/generate-manifest.js",
|
|
115
115
|
"regen-nonascii": "node scripts/regen-nonascii.js",
|
|
116
116
|
"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
|
|
5
|
+
export const EmitterTsTestLibrary: TypeSpecTestLibrary = createTestLibrary({
|
|
6
6
|
name: "emitter-ts",
|
|
7
7
|
packageRoot: resolvePath(fileURLToPath(import.meta.url), "../../../../"),
|
|
8
8
|
});
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
createTestWrapper,
|
|
5
5
|
expectDiagnosticEmpty,
|
|
6
6
|
} from "@typespec/compiler/testing";
|
|
7
|
-
import {
|
|
7
|
+
import { EmitterTsTestLibrary } from "../src/testing/index.js";
|
|
8
8
|
|
|
9
9
|
export async function createEmitterTsTestHost() {
|
|
10
10
|
return createTestHost({
|
|
11
|
-
libraries: [
|
|
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,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,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
|
|
6
|
-
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
|
+
});
|
|
@@ -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,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,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
|
+
});
|