@azure-tools/typespec-ts 0.56.0-dev.3 → 0.56.0-dev.4
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/CHANGELOG.md +9 -0
- package/README.md +31 -21
- package/dist/src/context-manager.d.ts +17 -0
- package/dist/src/context-manager.d.ts.map +1 -1
- package/dist/src/context-manager.js +21 -0
- package/dist/src/context-manager.js.map +1 -1
- package/dist/src/framework/declaration.d.ts.map +1 -1
- package/dist/src/framework/declaration.js +6 -20
- package/dist/src/framework/declaration.js.map +1 -1
- package/dist/src/framework/hooks/sdk-types.d.ts +9 -0
- package/dist/src/framework/hooks/sdk-types.d.ts.map +1 -1
- package/dist/src/framework/hooks/sdk-types.js +13 -0
- package/dist/src/framework/hooks/sdk-types.js.map +1 -1
- package/dist/src/framework/source-file-batch.d.ts +35 -0
- package/dist/src/framework/source-file-batch.d.ts.map +1 -0
- package/dist/src/framework/source-file-batch.js +128 -0
- package/dist/src/framework/source-file-batch.js.map +1 -0
- package/dist/src/index.js +12 -12
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces.d.ts +0 -2
- package/dist/src/interfaces.d.ts.map +1 -1
- package/dist/src/interfaces.js.map +1 -1
- package/dist/src/lib.d.ts +15 -2
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/src/lib.js +22 -11
- package/dist/src/lib.js.map +1 -1
- package/dist/src/metadata/build-package-file.d.ts +2 -4
- package/dist/src/metadata/build-package-file.d.ts.map +1 -1
- package/dist/src/metadata/build-package-file.js +2 -17
- package/dist/src/metadata/build-package-file.js.map +1 -1
- package/dist/src/metadata/build-readme-file.d.ts.map +1 -1
- package/dist/src/metadata/build-readme-file.js +17 -70
- package/dist/src/metadata/build-readme-file.js.map +1 -1
- package/dist/src/metadata/build-ts-config.d.ts.map +1 -1
- package/dist/src/metadata/build-ts-config.js +12 -0
- package/dist/src/metadata/build-ts-config.js.map +1 -1
- package/dist/src/metadata/package-json/build-azure-monorepo-package.d.ts +0 -1
- package/dist/src/metadata/package-json/build-azure-monorepo-package.d.ts.map +1 -1
- package/dist/src/metadata/package-json/build-azure-monorepo-package.js +0 -14
- package/dist/src/metadata/package-json/build-azure-monorepo-package.js.map +1 -1
- package/dist/src/metadata/render-template.d.ts +24 -0
- package/dist/src/metadata/render-template.d.ts.map +1 -0
- package/dist/src/metadata/render-template.js +148 -0
- package/dist/src/metadata/render-template.js.map +1 -0
- package/dist/src/metadata/test/build-recorded-client.d.ts.map +1 -1
- package/dist/src/metadata/test/build-recorded-client.js +1 -7
- package/dist/src/metadata/test/build-recorded-client.js.map +1 -1
- package/dist/src/metadata/test/build-sample-test.d.ts.map +1 -1
- package/dist/src/metadata/test/build-sample-test.js +1 -4
- package/dist/src/metadata/test/build-sample-test.js.map +1 -1
- package/dist/src/metadata/test/build-snippets.d.ts.map +1 -1
- package/dist/src/metadata/test/build-snippets.js +2 -4
- package/dist/src/metadata/test/build-snippets.js.map +1 -1
- package/dist/src/metadata/test/template.d.ts +0 -1
- package/dist/src/metadata/test/template.d.ts.map +1 -1
- package/dist/src/metadata/test/template.js +0 -127
- package/dist/src/metadata/test/template.js.map +1 -1
- package/dist/src/modular/build-classical-client.d.ts.map +1 -1
- package/dist/src/modular/build-classical-client.js +2 -2
- package/dist/src/modular/build-classical-client.js.map +1 -1
- package/dist/src/modular/build-root-index.d.ts.map +1 -1
- package/dist/src/modular/build-root-index.js +37 -9
- package/dist/src/modular/build-root-index.js.map +1 -1
- package/dist/src/modular/build-subpath-index.d.ts.map +1 -1
- package/dist/src/modular/build-subpath-index.js +15 -2
- package/dist/src/modular/build-subpath-index.js.map +1 -1
- package/dist/src/modular/emit-models.d.ts.map +1 -1
- package/dist/src/modular/emit-models.js +24 -17
- package/dist/src/modular/emit-models.js.map +1 -1
- package/dist/src/modular/helpers/client-helpers.d.ts +8 -3
- package/dist/src/modular/helpers/client-helpers.d.ts.map +1 -1
- package/dist/src/modular/helpers/client-helpers.js +37 -17
- package/dist/src/modular/helpers/client-helpers.js.map +1 -1
- package/dist/src/modular/helpers/operation-helpers.js +8 -9
- package/dist/src/modular/helpers/operation-helpers.js.map +1 -1
- package/dist/src/transform/transform-client-options.d.ts.map +1 -1
- package/dist/src/transform/transform-client-options.js +1 -5
- package/dist/src/transform/transform-client-options.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +30 -33
- package/src/context-manager.ts +23 -0
- package/src/framework/declaration.ts +8 -20
- package/src/framework/hooks/sdk-types.ts +14 -0
- package/src/framework/source-file-batch.ts +140 -0
- package/src/index.ts +13 -13
- package/src/interfaces.ts +0 -2
- package/src/lib.ts +40 -14
- package/src/metadata/build-package-file.ts +2 -21
- package/src/metadata/build-readme-file.ts +20 -94
- package/src/metadata/build-ts-config.ts +12 -0
- package/src/metadata/package-json/build-azure-monorepo-package.ts +0 -17
- package/src/metadata/render-template.ts +202 -0
- package/src/metadata/test/build-recorded-client.ts +1 -7
- package/src/metadata/test/build-sample-test.ts +1 -4
- package/src/metadata/test/build-snippets.ts +2 -4
- package/src/metadata/test/template.ts +0 -128
- package/src/modular/build-classical-client.ts +2 -6
- package/src/modular/build-root-index.ts +52 -14
- package/src/modular/build-subpath-index.ts +24 -3
- package/src/modular/emit-models.ts +24 -18
- package/src/modular/helpers/client-helpers.ts +43 -25
- package/src/modular/helpers/operation-helpers.ts +10 -10
- package/src/transform/transform-client-options.ts +1 -5
|
@@ -1,131 +1,3 @@
|
|
|
1
|
-
export const karmaConfig = `
|
|
2
|
-
// https://github.com/karma-runner/karma-chrome-launcher
|
|
3
|
-
process.env.CHROME_BIN = require("puppeteer").executablePath();
|
|
4
|
-
require("dotenv").config();
|
|
5
|
-
const { relativeRecordingsPath } = require("@azure-tools/test-recorder");
|
|
6
|
-
process.env.RECORDINGS_RELATIVE_PATH = relativeRecordingsPath();
|
|
7
|
-
|
|
8
|
-
module.exports = function (config) {
|
|
9
|
-
config.set({
|
|
10
|
-
// base path that will be used to resolve all patterns (eg. files, exclude)
|
|
11
|
-
basePath: "./",
|
|
12
|
-
|
|
13
|
-
// frameworks to use
|
|
14
|
-
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
|
|
15
|
-
frameworks: ["source-map-support", "mocha"],
|
|
16
|
-
|
|
17
|
-
plugins: [
|
|
18
|
-
"karma-mocha",
|
|
19
|
-
"karma-mocha-reporter",
|
|
20
|
-
"karma-chrome-launcher",
|
|
21
|
-
"karma-firefox-launcher",
|
|
22
|
-
"karma-env-preprocessor",
|
|
23
|
-
"karma-coverage",
|
|
24
|
-
"karma-sourcemap-loader",
|
|
25
|
-
"karma-junit-reporter",
|
|
26
|
-
"karma-source-map-support",
|
|
27
|
-
],
|
|
28
|
-
|
|
29
|
-
// list of files / patterns to load in the browser
|
|
30
|
-
files: [
|
|
31
|
-
"dist-test/index.browser.js",
|
|
32
|
-
{ pattern: "dist-test/index.browser.js.map", type: "html", included: false, served: true },
|
|
33
|
-
],
|
|
34
|
-
|
|
35
|
-
// list of files / patterns to exclude
|
|
36
|
-
exclude: [],
|
|
37
|
-
|
|
38
|
-
// preprocess matching files before serving them to the browser
|
|
39
|
-
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
|
|
40
|
-
preprocessors: {
|
|
41
|
-
"**/*.js": ["sourcemap", "env"],
|
|
42
|
-
// IMPORTANT: COMMENT following line if you want to debug in your browsers!!
|
|
43
|
-
// Preprocess source file to calculate code coverage, however this will make source file unreadable
|
|
44
|
-
// "dist-test/index.js": ["coverage"]
|
|
45
|
-
},
|
|
46
|
-
|
|
47
|
-
envPreprocessor: [
|
|
48
|
-
"TEST_MODE",
|
|
49
|
-
"ENDPOINT",
|
|
50
|
-
"AZURE_CLIENT_SECRET",
|
|
51
|
-
"AZURE_CLIENT_ID",
|
|
52
|
-
"AZURE_TENANT_ID",
|
|
53
|
-
"SUBSCRIPTION_ID",
|
|
54
|
-
"RECORDINGS_RELATIVE_PATH",
|
|
55
|
-
],
|
|
56
|
-
|
|
57
|
-
// test results reporter to use
|
|
58
|
-
// possible values: 'dots', 'progress'
|
|
59
|
-
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
|
60
|
-
reporters: ["mocha", "coverage", "junit"],
|
|
61
|
-
|
|
62
|
-
coverageReporter: {
|
|
63
|
-
// specify a common output directory
|
|
64
|
-
dir: "coverage-browser/",
|
|
65
|
-
reporters: [
|
|
66
|
-
{ type: "json", subdir: ".", file: "coverage.json" },
|
|
67
|
-
{ type: "lcovonly", subdir: ".", file: "lcov.info" },
|
|
68
|
-
{ type: "html", subdir: "html" },
|
|
69
|
-
{ type: "cobertura", subdir: ".", file: "cobertura-coverage.xml" },
|
|
70
|
-
],
|
|
71
|
-
},
|
|
72
|
-
|
|
73
|
-
junitReporter: {
|
|
74
|
-
outputDir: "", // results will be saved as $outputDir/$browserName.xml
|
|
75
|
-
outputFile: "test-results.browser.xml", // if included, results will be saved as $outputDir/$browserName/$outputFile
|
|
76
|
-
suite: "", // suite will become the package name attribute in xml testsuite element
|
|
77
|
-
useBrowserName: false, // add browser name to report and classes names
|
|
78
|
-
nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element
|
|
79
|
-
classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element
|
|
80
|
-
properties: {}, // key value pair of properties to add to the <properties> section of the report
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
// web server port
|
|
84
|
-
port: 9876,
|
|
85
|
-
|
|
86
|
-
// enable / disable colors in the output (reporters and logs)
|
|
87
|
-
colors: true,
|
|
88
|
-
|
|
89
|
-
// level of logging
|
|
90
|
-
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
|
91
|
-
logLevel: config.LOG_INFO,
|
|
92
|
-
|
|
93
|
-
// enable / disable watching file and executing tests whenever any file changes
|
|
94
|
-
autoWatch: false,
|
|
95
|
-
|
|
96
|
-
// --no-sandbox allows our tests to run in Linux without having to change the system.
|
|
97
|
-
// --disable-web-security allows us to authenticate from the browser without having to write tests using interactive auth, which would be far more complex.
|
|
98
|
-
browsers: ["ChromeHeadlessNoSandbox"],
|
|
99
|
-
customLaunchers: {
|
|
100
|
-
ChromeHeadlessNoSandbox: {
|
|
101
|
-
base: "ChromeHeadless",
|
|
102
|
-
flags: ["--no-sandbox", "--disable-web-security"],
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
// Continuous Integration mode
|
|
107
|
-
// if true, Karma captures browsers, runs the tests and exits
|
|
108
|
-
singleRun: false,
|
|
109
|
-
|
|
110
|
-
// Concurrency level
|
|
111
|
-
// how many browser should be started simultaneous
|
|
112
|
-
concurrency: 1,
|
|
113
|
-
|
|
114
|
-
browserNoActivityTimeout: 60000000,
|
|
115
|
-
browserDisconnectTimeout: 10000,
|
|
116
|
-
browserDisconnectTolerance: 3,
|
|
117
|
-
|
|
118
|
-
client: {
|
|
119
|
-
mocha: {
|
|
120
|
-
// change Karma's debug.html to the mocha web reporter
|
|
121
|
-
reporter: "html",
|
|
122
|
-
timeout: "600000",
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
};
|
|
127
|
-
`;
|
|
128
|
-
|
|
129
1
|
export const recordedClientContent = `
|
|
130
2
|
|
|
131
3
|
import {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
SourceFile,
|
|
6
6
|
StructureKind,
|
|
7
7
|
} from "ts-morph";
|
|
8
|
-
import {
|
|
8
|
+
import { getClientParametersDeclaration } from "./helpers/client-helpers.js";
|
|
9
9
|
import { getClassicalClientName, getClientName } from "./helpers/naming-helpers.js";
|
|
10
10
|
import { ModularEmitterOptions } from "./interfaces.js";
|
|
11
11
|
|
|
@@ -127,11 +127,7 @@ export function buildClassicalClient(
|
|
|
127
127
|
.map((p) => p.name)
|
|
128
128
|
.map((x) => {
|
|
129
129
|
if (x === "options") {
|
|
130
|
-
return `
|
|
131
|
-
constructor,
|
|
132
|
-
emitterOptions,
|
|
133
|
-
"azsdk-js-client",
|
|
134
|
-
)}}`;
|
|
130
|
+
return `options`;
|
|
135
131
|
} else if (x.toLowerCase() === "subscriptionid" && shouldSubscriptionIdOptional) {
|
|
136
132
|
return `subscriptionId ?? ""`;
|
|
137
133
|
} else {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { SdkClientType, SdkServiceOperation } from "@azure-tools/typespec-client-generator-core";
|
|
2
2
|
import { joinPaths, NoTarget } from "@typespec/compiler";
|
|
3
|
-
import { Project, SourceFile } from "ts-morph";
|
|
3
|
+
import { Project, SourceFile, StructureKind } from "ts-morph";
|
|
4
4
|
import { useContext } from "../context-manager.js";
|
|
5
5
|
import { resolveReference } from "../framework/reference.js";
|
|
6
|
+
import {
|
|
7
|
+
beginSourceFileBatch,
|
|
8
|
+
enqueueStatement,
|
|
9
|
+
flushSourceFileBatch,
|
|
10
|
+
getEffectiveExportedNames,
|
|
11
|
+
getQueuedExportNames,
|
|
12
|
+
} from "../framework/source-file-batch.js";
|
|
6
13
|
import { reportDiagnostic } from "../lib.js";
|
|
7
14
|
import { getClientModuleInfo } from "../utils/client-utils.js";
|
|
8
15
|
import { SdkContext } from "../utils/interfaces.js";
|
|
@@ -24,6 +31,20 @@ export function buildRootIndex(
|
|
|
24
31
|
emitterOptions: ModularEmitterOptions,
|
|
25
32
|
rootIndexFile: SourceFile,
|
|
26
33
|
clientMap?: [string[], SdkClientType<SdkServiceOperation>],
|
|
34
|
+
) {
|
|
35
|
+
beginSourceFileBatch();
|
|
36
|
+
try {
|
|
37
|
+
buildRootIndexImpl(context, emitterOptions, rootIndexFile, clientMap);
|
|
38
|
+
} finally {
|
|
39
|
+
flushSourceFileBatch();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildRootIndexImpl(
|
|
44
|
+
context: SdkContext,
|
|
45
|
+
emitterOptions: ModularEmitterOptions,
|
|
46
|
+
rootIndexFile: SourceFile,
|
|
47
|
+
clientMap?: [string[], SdkClientType<SdkServiceOperation>],
|
|
27
48
|
) {
|
|
28
49
|
if (!clientMap) {
|
|
29
50
|
// we still need to export the models if no client is provided
|
|
@@ -109,7 +130,8 @@ function exportRestErrorTypes(rootIndexFile: SourceFile) {
|
|
|
109
130
|
const existingExports = getExistingExports(rootIndexFile);
|
|
110
131
|
const namedExports = ["RestError", "isRestError"].filter((name) => !existingExports.has(name));
|
|
111
132
|
if (namedExports.length > 0) {
|
|
112
|
-
rootIndexFile
|
|
133
|
+
enqueueStatement(rootIndexFile, {
|
|
134
|
+
kind: StructureKind.ExportDeclaration,
|
|
113
135
|
moduleSpecifier: "@azure/core-rest-pipeline",
|
|
114
136
|
namedExports,
|
|
115
137
|
});
|
|
@@ -165,13 +187,7 @@ function exportFileContentsType(context: SdkContext, rootIndexFile: SourceFile)
|
|
|
165
187
|
}
|
|
166
188
|
|
|
167
189
|
function getExistingExports(rootIndexFile: SourceFile): Set<string> {
|
|
168
|
-
return
|
|
169
|
-
rootIndexFile
|
|
170
|
-
.getExportDeclarations()
|
|
171
|
-
.flatMap((exportDecl) =>
|
|
172
|
-
exportDecl.getNamedExports().map((namedExport) => namedExport.getName()),
|
|
173
|
-
),
|
|
174
|
-
);
|
|
190
|
+
return getEffectiveExportedNames(rootIndexFile);
|
|
175
191
|
}
|
|
176
192
|
|
|
177
193
|
function getNewNamedExports(namedExports: string[], existingExports: Set<string>): string[] {
|
|
@@ -186,7 +202,8 @@ function addExportsToRootIndexFile(
|
|
|
186
202
|
const existingExports = getExistingExports(rootIndexFile);
|
|
187
203
|
const newNamedExports = getNewNamedExports(namedExports, existingExports);
|
|
188
204
|
if (newNamedExports.length > 0) {
|
|
189
|
-
rootIndexFile
|
|
205
|
+
enqueueStatement(rootIndexFile, {
|
|
206
|
+
kind: StructureKind.ExportDeclaration,
|
|
190
207
|
isTypeOnly,
|
|
191
208
|
namedExports: newNamedExports,
|
|
192
209
|
});
|
|
@@ -222,7 +239,8 @@ function exportSimplePollerLike(
|
|
|
222
239
|
const moduleSpecifier = `./${
|
|
223
240
|
isTopLevel && subfolder && subfolder !== "" ? subfolder + "/" : ""
|
|
224
241
|
}static-helpers/simplePollerHelpers.js`;
|
|
225
|
-
indexFile
|
|
242
|
+
enqueueStatement(indexFile, {
|
|
243
|
+
kind: StructureKind.ExportDeclaration,
|
|
226
244
|
isTypeOnly: true,
|
|
227
245
|
moduleSpecifier,
|
|
228
246
|
namedExports: ["SimplePollerLike"],
|
|
@@ -243,7 +261,10 @@ function exportRestoreHelpers(
|
|
|
243
261
|
if (!helperFile) {
|
|
244
262
|
return;
|
|
245
263
|
}
|
|
246
|
-
const exported = new Set(
|
|
264
|
+
const exported = new Set([
|
|
265
|
+
...indexFile.getExportedDeclarations().keys(),
|
|
266
|
+
...getQueuedExportNames(indexFile),
|
|
267
|
+
]);
|
|
247
268
|
const allEntries = [...helperFile.getExportedDeclarations().entries()];
|
|
248
269
|
const moduleSpecifier = `./${
|
|
249
270
|
isTopLevel && subfolder && subfolder !== "" ? subfolder + "/" : ""
|
|
@@ -259,7 +280,8 @@ function exportClassicalClient(
|
|
|
259
280
|
isSubClient: boolean = false,
|
|
260
281
|
) {
|
|
261
282
|
const clientName = client.name;
|
|
262
|
-
indexFile
|
|
283
|
+
enqueueStatement(indexFile, {
|
|
284
|
+
kind: StructureKind.ExportDeclaration,
|
|
263
285
|
namedExports: [clientName],
|
|
264
286
|
moduleSpecifier: `./${
|
|
265
287
|
subfolder && subfolder !== "" && !isSubClient ? subfolder + "/" : ""
|
|
@@ -321,7 +343,10 @@ function exportModules(
|
|
|
321
343
|
continue;
|
|
322
344
|
}
|
|
323
345
|
|
|
324
|
-
const exported = new Set(
|
|
346
|
+
const exported = new Set([
|
|
347
|
+
...indexFile.getExportedDeclarations().keys(),
|
|
348
|
+
...getQueuedExportNames(indexFile),
|
|
349
|
+
]);
|
|
325
350
|
const serializerOrDeserializerRegex = /.*(Serializer|Deserializer)(_\d+)?$/;
|
|
326
351
|
const filteredEntries = [...modelsFile.getExportedDeclarations().entries()].filter(
|
|
327
352
|
(exDeclaration) => {
|
|
@@ -362,6 +387,19 @@ export function buildSubClientIndexFile(
|
|
|
362
387
|
context: SdkContext,
|
|
363
388
|
clientMap: [string[], SdkClientType<SdkServiceOperation>],
|
|
364
389
|
emitterOptions: ModularEmitterOptions,
|
|
390
|
+
) {
|
|
391
|
+
beginSourceFileBatch();
|
|
392
|
+
try {
|
|
393
|
+
buildSubClientIndexFileImpl(context, clientMap, emitterOptions);
|
|
394
|
+
} finally {
|
|
395
|
+
flushSourceFileBatch();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function buildSubClientIndexFileImpl(
|
|
400
|
+
context: SdkContext,
|
|
401
|
+
clientMap: [string[], SdkClientType<SdkServiceOperation>],
|
|
402
|
+
emitterOptions: ModularEmitterOptions,
|
|
365
403
|
) {
|
|
366
404
|
const project = useContext("outputProject");
|
|
367
405
|
const [_, client] = clientMap;
|
|
@@ -2,8 +2,13 @@ import { SdkClientType, SdkServiceOperation } from "@azure-tools/typespec-client
|
|
|
2
2
|
import { joinPaths } from "@typespec/compiler";
|
|
3
3
|
import { ModularEmitterOptions } from "./interfaces.js";
|
|
4
4
|
|
|
5
|
-
import { Node, SourceFile } from "ts-morph";
|
|
5
|
+
import { Node, SourceFile, StructureKind } from "ts-morph";
|
|
6
6
|
import { useContext } from "../context-manager.js";
|
|
7
|
+
import {
|
|
8
|
+
beginSourceFileBatch,
|
|
9
|
+
enqueueStatement,
|
|
10
|
+
flushSourceFileBatch,
|
|
11
|
+
} from "../framework/source-file-batch.js";
|
|
7
12
|
import { getClientModuleInfo } from "../utils/client-utils.js";
|
|
8
13
|
|
|
9
14
|
export interface buildSubpathIndexFileOptions {
|
|
@@ -17,6 +22,20 @@ export function buildSubpathIndexFile(
|
|
|
17
22
|
subpath: string,
|
|
18
23
|
clientMap?: [string[], SdkClientType<SdkServiceOperation>],
|
|
19
24
|
options: buildSubpathIndexFileOptions = {},
|
|
25
|
+
) {
|
|
26
|
+
beginSourceFileBatch();
|
|
27
|
+
try {
|
|
28
|
+
buildSubpathIndexFileImpl(emitterOptions, subpath, clientMap, options);
|
|
29
|
+
} finally {
|
|
30
|
+
flushSourceFileBatch();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function buildSubpathIndexFileImpl(
|
|
35
|
+
emitterOptions: ModularEmitterOptions,
|
|
36
|
+
subpath: string,
|
|
37
|
+
clientMap?: [string[], SdkClientType<SdkServiceOperation>],
|
|
38
|
+
options: buildSubpathIndexFileOptions = {},
|
|
20
39
|
) {
|
|
21
40
|
const project = useContext("outputProject");
|
|
22
41
|
const subfolder = clientMap ? (getClientModuleInfo(clientMap).subfolder ?? "") : "";
|
|
@@ -137,14 +156,16 @@ export function partitionAndEmitExports(
|
|
|
137
156
|
}
|
|
138
157
|
}
|
|
139
158
|
if (typeOnlyExports.length > 0) {
|
|
140
|
-
indexFile
|
|
159
|
+
enqueueStatement(indexFile, {
|
|
160
|
+
kind: StructureKind.ExportDeclaration,
|
|
141
161
|
isTypeOnly: true,
|
|
142
162
|
moduleSpecifier,
|
|
143
163
|
namedExports: typeOnlyExports,
|
|
144
164
|
});
|
|
145
165
|
}
|
|
146
166
|
if (valueExports.length > 0) {
|
|
147
|
-
indexFile
|
|
167
|
+
enqueueStatement(indexFile, {
|
|
168
|
+
kind: StructureKind.ExportDeclaration,
|
|
148
169
|
moduleSpecifier,
|
|
149
170
|
namedExports: valueExports,
|
|
150
171
|
});
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
pagedModelsKeptPublic,
|
|
47
47
|
} from "../framework/hooks/sdk-types.js";
|
|
48
48
|
import { refkey } from "../framework/refkey.js";
|
|
49
|
+
import { beginSourceFileBatch, flushSourceFileBatch } from "../framework/source-file-batch.js";
|
|
49
50
|
import { reportDiagnostic } from "../lib.js";
|
|
50
51
|
import { getClientHierarchyMap } from "../utils/client-utils.js";
|
|
51
52
|
import { SdkContext } from "../utils/interfaces.js";
|
|
@@ -117,32 +118,37 @@ export function emitTypes(context: SdkContext, { sourceRoot }: { sourceRoot: str
|
|
|
117
118
|
|
|
118
119
|
let sourceFile;
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
beginSourceFileBatch();
|
|
122
|
+
try {
|
|
123
|
+
for (const type of emitQueue) {
|
|
124
|
+
if (!isGenerableType(type)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
const namespaces = getModelNamespaces(context, type);
|
|
129
|
+
const filepath = getModelsPath(sourceRoot, namespaces);
|
|
130
|
+
sourceFile = outputProject.getSourceFile(filepath);
|
|
131
|
+
if (!sourceFile) {
|
|
132
|
+
sourceFile = outputProject.createSourceFile(filepath);
|
|
133
|
+
sourceFile.addStatements(`/*
|
|
131
134
|
* This file contains only generated model types and their (de)serializers.
|
|
132
135
|
* Disable the following rules for internal models with '_' prefix and deserializers which require 'any' for raw JSON input.
|
|
133
136
|
*/
|
|
134
137
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
135
138
|
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */`);
|
|
139
|
+
}
|
|
140
|
+
emitType(context, type, sourceFile);
|
|
136
141
|
}
|
|
137
|
-
emitType(context, type, sourceFile);
|
|
138
|
-
}
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
// Emit serialization/deserialization functions for flattened properties
|
|
144
|
+
for (const [property, _] of flattenPropertyModelMap) {
|
|
145
|
+
const namespaces = getModelNamespaces(context, property.type);
|
|
146
|
+
const filepath = getModelsPath(sourceRoot, namespaces);
|
|
147
|
+
sourceFile = outputProject.getSourceFile(filepath);
|
|
148
|
+
addSerializationFunctions(context, property, sourceFile!);
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
flushSourceFileBatch();
|
|
146
152
|
}
|
|
147
153
|
|
|
148
154
|
const modelFiles = outputProject.getSourceFiles(sourceRoot + "/models/**/*.ts");
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
SdkMethodParameter,
|
|
7
7
|
SdkServiceOperation,
|
|
8
8
|
} from "@azure-tools/typespec-client-generator-core";
|
|
9
|
-
import { OptionalKind, ParameterDeclarationStructure, StatementedNode } from "ts-morph";
|
|
9
|
+
import { Node, OptionalKind, ParameterDeclarationStructure, StatementedNode } from "ts-morph";
|
|
10
10
|
import { ModularEmitterOptions } from "../interfaces.js";
|
|
11
11
|
|
|
12
12
|
import { resolveReference } from "../../framework/reference.js";
|
|
@@ -236,12 +236,12 @@ export function buildGetClientEndpointParam(
|
|
|
236
236
|
* @returns - an expression representing the options to be passed in to getClient
|
|
237
237
|
*/
|
|
238
238
|
export function buildGetClientOptionsParam(
|
|
239
|
-
context: StatementedNode,
|
|
239
|
+
context: StatementedNode & Node,
|
|
240
240
|
emitterOptions: ModularEmitterOptions,
|
|
241
241
|
endpointParam: string,
|
|
242
242
|
apiVersionParamName?: string,
|
|
243
243
|
): string {
|
|
244
|
-
const userAgentOptions = buildUserAgentOptions(context, emitterOptions
|
|
244
|
+
const userAgentOptions = buildUserAgentOptions(context, emitterOptions);
|
|
245
245
|
const loggingOptions = buildLoggingOptions();
|
|
246
246
|
const credentials = buildCredentials(emitterOptions, endpointParam);
|
|
247
247
|
|
|
@@ -313,37 +313,55 @@ function buildLoggingOptions(): string | undefined {
|
|
|
313
313
|
return `{ logger: options.loggingOptions?.logger ?? logger.info }`;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
/**
|
|
317
|
+
* Builds the `userAgentOptions` for the generated client, producing a telemetry
|
|
318
|
+
* prefix of the form `[<application_id> ]azsdk-js-<package>/<version>` per the Azure
|
|
319
|
+
* Core telemetry policy: https://azure.github.io/azure-sdk/general_azurecore.html#telemetry-policy
|
|
320
|
+
*/
|
|
316
321
|
export function buildUserAgentOptions(
|
|
317
|
-
context: StatementedNode,
|
|
322
|
+
context: StatementedNode & Node,
|
|
318
323
|
emitterOptions: ModularEmitterOptions,
|
|
319
|
-
sdkUserAgentPrefix: string,
|
|
320
324
|
): string {
|
|
321
325
|
const userAgentStatements = [];
|
|
322
326
|
const prefixFromOptions = "const prefixFromOptions = options?.userAgentOptions?.userAgentPrefix;";
|
|
323
327
|
userAgentStatements.push(prefixFromOptions);
|
|
324
328
|
|
|
329
|
+
const packageName = emitterOptions.options.packageDetails?.name;
|
|
325
330
|
const clientPackageName =
|
|
326
|
-
emitterOptions.options.packageDetails?.nameWithoutScope ??
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
331
|
+
emitterOptions.options.packageDetails?.nameWithoutScope ?? packageName ?? "";
|
|
332
|
+
|
|
333
|
+
// The version is read from the generated package.json at runtime rather than
|
|
334
|
+
// hardcoded here: once the package is generated, its version is owned by
|
|
335
|
+
// package.json. We import it via the package's own "./package.json" export so
|
|
336
|
+
// the specifier is identical in `src` and the built `dist` output.
|
|
337
|
+
let userAgentInfoStatement = "";
|
|
338
|
+
if (clientPackageName && packageName) {
|
|
339
|
+
const packageJsonModule = `${packageName}/package.json`;
|
|
340
|
+
const sourceFile = context.getSourceFile();
|
|
341
|
+
const hasPackageJsonImport = sourceFile
|
|
342
|
+
.getImportDeclarations()
|
|
343
|
+
.some((declaration) => declaration.getModuleSpecifierValue() === packageJsonModule);
|
|
344
|
+
if (!hasPackageJsonImport) {
|
|
345
|
+
sourceFile.addImportDeclaration({
|
|
346
|
+
defaultImport: "pkgJson",
|
|
347
|
+
moduleSpecifier: packageJsonModule,
|
|
348
|
+
attributes: [{ name: "type", value: "json" }],
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
userAgentInfoStatement =
|
|
352
|
+
"const userAgentInfo = `azsdk-js-" + clientPackageName + "/${pkgJson.version}`;";
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!userAgentInfoStatement) {
|
|
356
|
+
// Without package name/version we cannot build a meaningful telemetry token,
|
|
357
|
+
// so we leave the user agent untouched (the caller's userAgentOptions still flow
|
|
358
|
+
// through `...options`) and let core-rest-pipeline defaults apply.
|
|
359
|
+
return "";
|
|
338
360
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
"` : `" +
|
|
344
|
-
`${sdkUserAgentPrefix}` +
|
|
345
|
-
`${userAgentInfoStatement ? " ${userAgentInfo}`" : "`"}`
|
|
346
|
-
};`;
|
|
361
|
+
|
|
362
|
+
userAgentStatements.push(userAgentInfoStatement);
|
|
363
|
+
const userAgentPrefix =
|
|
364
|
+
"const userAgentPrefix = prefixFromOptions ? `${prefixFromOptions} ${userAgentInfo}` : `${userAgentInfo}`;";
|
|
347
365
|
userAgentStatements.push(userAgentPrefix);
|
|
348
366
|
|
|
349
367
|
context.addStatements(userAgentStatements.join("\n"));
|
|
@@ -213,11 +213,11 @@ export function getDeserializePrivateFunction(
|
|
|
213
213
|
};
|
|
214
214
|
} else if (response.type) {
|
|
215
215
|
// When response.optional is true, some HTTP responses have no body (e.g. 204), so
|
|
216
|
-
// the return type must include
|
|
216
|
+
// the return type must include void to reflect that possibility.
|
|
217
217
|
const baseType = getTypeExpression(context, response.type);
|
|
218
218
|
returnType = {
|
|
219
219
|
name: (response as any).name ?? "",
|
|
220
|
-
type: response.optional ? `${baseType} |
|
|
220
|
+
type: response.optional ? `${baseType} | void` : baseType,
|
|
221
221
|
};
|
|
222
222
|
} else if (isHeadAsBooleanOperation(operation)) {
|
|
223
223
|
returnType = { name: "", type: "boolean" };
|
|
@@ -405,15 +405,15 @@ export function getDeserializePrivateFunction(
|
|
|
405
405
|
}
|
|
406
406
|
if (deserializeFunctionName) {
|
|
407
407
|
if (needsBodyGuard) {
|
|
408
|
-
// Use ternary form: return result.body ? deserializer(result.body) : undefined
|
|
409
408
|
statements.push(
|
|
410
|
-
`
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
statements.push(
|
|
414
|
-
`return ${deserializeFunctionName}(${deserializedRoot})${multipartCastSuffix}`,
|
|
409
|
+
`if (!${deserializedRoot}) {
|
|
410
|
+
return;
|
|
411
|
+
}`,
|
|
415
412
|
);
|
|
416
413
|
}
|
|
414
|
+
statements.push(
|
|
415
|
+
`return ${deserializeFunctionName}(${deserializedRoot})${multipartCastSuffix}`,
|
|
416
|
+
);
|
|
417
417
|
} else if (isAzureCoreErrorType(context.program, deserializedType.__raw)) {
|
|
418
418
|
statements.push(`return ${deserializedRoot}${multipartCastSuffix}`);
|
|
419
419
|
} else if (isHeadAsBooleanOperation(operation)) {
|
|
@@ -949,13 +949,13 @@ export function getOperationFunction(
|
|
|
949
949
|
const baseCompositeType = buildCompositeResponseType(context, type, responseHeaders);
|
|
950
950
|
returnType = {
|
|
951
951
|
name: (type as any).name ?? "",
|
|
952
|
-
type: response.optional ? `${baseCompositeType} |
|
|
952
|
+
type: response.optional ? `${baseCompositeType} | void` : baseCompositeType,
|
|
953
953
|
};
|
|
954
954
|
} else {
|
|
955
955
|
const baseType = getTypeExpression(context, type!);
|
|
956
956
|
returnType = {
|
|
957
957
|
name: (type as any).name ?? "",
|
|
958
|
-
type: response.optional ? `${baseType} |
|
|
958
|
+
type: response.optional ? `${baseType} | void` : baseType,
|
|
959
959
|
};
|
|
960
960
|
}
|
|
961
961
|
} else if (hasHeaderOnlyResponse && isResponseHeadersEnabled) {
|
|
@@ -44,7 +44,6 @@ function extractClientOptions(
|
|
|
44
44
|
const enableModelNamespace = getEnableModelNamespace(dpgContext, emitterOptions);
|
|
45
45
|
const hierarchyClient = getHierarchyClient(emitterOptions);
|
|
46
46
|
const clearOutputFolder = getClearOutputFolder(emitterOptions);
|
|
47
|
-
const isTypeSpecTest = emitterOptions["is-typespec-test"];
|
|
48
47
|
const compatibilityMode = emitterOptions["compatibility-mode"];
|
|
49
48
|
const compatibilityLro = emitterOptions["compatibility-lro"];
|
|
50
49
|
const experimentalExtensibleEnums = emitterOptions["experimental-extensible-enums"];
|
|
@@ -73,7 +72,6 @@ function extractClientOptions(
|
|
|
73
72
|
hierarchyClient,
|
|
74
73
|
azureArm: dpgContext.arm,
|
|
75
74
|
clearOutputFolder,
|
|
76
|
-
isTypeSpecTest,
|
|
77
75
|
compatibilityMode,
|
|
78
76
|
compatibilityLro,
|
|
79
77
|
experimentalExtensibleEnums,
|
|
@@ -234,14 +232,12 @@ function buildPackageDetails(program: Program, emitterOptions: EmitterOptions):
|
|
|
234
232
|
nameWithoutScope: "unamedpackage",
|
|
235
233
|
version: "1.0.0-beta.1",
|
|
236
234
|
};
|
|
237
|
-
const isVersionUserProvided = Boolean(emitterOptions["package-details"]?.version);
|
|
238
235
|
const packageDetails: PackageDetails = {
|
|
239
236
|
...emitterOptions["package-details"],
|
|
240
237
|
name:
|
|
241
238
|
emitterOptions["package-details"]?.name ??
|
|
242
239
|
normalizeName(getDefaultService(program)?.title ?? "", NameType.Class),
|
|
243
|
-
version: emitterOptions["package-details"]?.version
|
|
244
|
-
isVersionUserProvided,
|
|
240
|
+
version: emitterOptions["package-details"]?.version,
|
|
245
241
|
};
|
|
246
242
|
if (emitterOptions["package-details"]?.name) {
|
|
247
243
|
const nameParts = emitterOptions["package-details"]?.name.split("/");
|