From 01773021f2f5272f52dddaee3bd2cbc92897c409 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 08:36:16 -0700 Subject: [PATCH 01/35] Add boilerplate --- docs/libraries/xml/reference/index.mdx | 34 +++++++++ packages/xml/.eslintrc.cjs | 7 ++ packages/xml/README.md | 9 +++ packages/xml/lib/decorators.tsp | 3 + packages/xml/lib/main.tsp | 2 + packages/xml/package.json | 65 ++++++++++++++++ packages/xml/src/decorators.ts | 1 + packages/xml/src/index.ts | 1 + packages/xml/src/lib.ts | 7 ++ packages/xml/src/testing/index.ts | 10 +++ packages/xml/test/decorators.test.ts | 3 + packages/xml/test/test-host.ts | 12 +++ packages/xml/tsconfig.config.json | 4 + packages/xml/tsconfig.json | 11 +++ packages/xml/vitest.config.ts | 4 + pnpm-lock.yaml | 101 ++++++++++++++++++------- tsconfig.ws.json | 3 +- 17 files changed, 247 insertions(+), 30 deletions(-) create mode 100644 docs/libraries/xml/reference/index.mdx create mode 100644 packages/xml/.eslintrc.cjs create mode 100644 packages/xml/README.md create mode 100644 packages/xml/lib/decorators.tsp create mode 100644 packages/xml/lib/main.tsp create mode 100644 packages/xml/package.json create mode 100644 packages/xml/src/decorators.ts create mode 100644 packages/xml/src/index.ts create mode 100644 packages/xml/src/lib.ts create mode 100644 packages/xml/src/testing/index.ts create mode 100644 packages/xml/test/decorators.test.ts create mode 100644 packages/xml/test/test-host.ts create mode 100644 packages/xml/tsconfig.config.json create mode 100644 packages/xml/tsconfig.json create mode 100644 packages/xml/vitest.config.ts diff --git a/docs/libraries/xml/reference/index.mdx b/docs/libraries/xml/reference/index.mdx new file mode 100644 index 0000000000..1beec4911f --- /dev/null +++ b/docs/libraries/xml/reference/index.mdx @@ -0,0 +1,34 @@ +--- +title: Overview +sidebar_position: 0 +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Overview + +TypeSpec library providing xml bindings + +## Install + + + + +```bash +npm install @typespec/xml +``` + + + + +```bash +npm install --save-peer @typespec/xml +``` + + + + +## TypeSpec.Xml diff --git a/packages/xml/.eslintrc.cjs b/packages/xml/.eslintrc.cjs new file mode 100644 index 0000000000..bed8471c3f --- /dev/null +++ b/packages/xml/.eslintrc.cjs @@ -0,0 +1,7 @@ +require("@typespec/eslint-config-typespec/patch/modern-module-resolution"); + +module.exports = { + plugins: ["@typespec/eslint-plugin"], + extends: ["@typespec/eslint-config-typespec", "plugin:@typespec/eslint-plugin/recommended"], + parserOptions: { tsconfigRootDir: __dirname, project: "tsconfig.config.json" }, +}; diff --git a/packages/xml/README.md b/packages/xml/README.md new file mode 100644 index 0000000000..da68f38cab --- /dev/null +++ b/packages/xml/README.md @@ -0,0 +1,9 @@ +# @typespec/xml + +TypeSpec library providing xml bindings + +## Install + +```bash +npm install @typespec/xml +``` diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp new file mode 100644 index 0000000000..bd0fbf6177 --- /dev/null +++ b/packages/xml/lib/decorators.tsp @@ -0,0 +1,3 @@ +using TypeSpec.Reflection; + +namespace TypeSpec.Xml; diff --git a/packages/xml/lib/main.tsp b/packages/xml/lib/main.tsp new file mode 100644 index 0000000000..9847aa0002 --- /dev/null +++ b/packages/xml/lib/main.tsp @@ -0,0 +1,2 @@ +import "../dist/src/index.js"; +import "./decorators.tsp"; diff --git a/packages/xml/package.json b/packages/xml/package.json new file mode 100644 index 0000000000..f2e023efe0 --- /dev/null +++ b/packages/xml/package.json @@ -0,0 +1,65 @@ +{ + "name": "@typespec/xml", + "version": "0.54.0", + "author": "Microsoft Corporation", + "description": "TypeSpec library providing xml bindings", + "homepage": "https://typespec.io", + "readme": "https://github.com/microsoft/typespec/blob/main/README.md", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/microsoft/typespec.git" + }, + "bugs": { + "url": "https://github.com/microsoft/typespec/issues" + }, + "keywords": [ + "typespec" + ], + "type": "module", + "main": "dist/src/index.js", + "tspMain": "lib/main.tsp", + "exports": { + ".": "./dist/src/index.js", + "./testing": "./dist/src/testing/index.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "scripts": { + "clean": "rimraf ./dist ./temp", + "build": "npm run gen-extern-signature && tsc -p . && npm run lint-typespec-library", + "watch": "tsc -p . --watch", + "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", + "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", + "test": "vitest run", + "test:ui": "vitest --ui", + "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism", + "lint": "eslint . --ext .ts --max-warnings=0", + "lint:fix": "eslint . --fix --ext .ts", + "regen-docs": "tspd doc . --enable-experimental --output-dir ../../docs/libraries/xml/reference" + }, + "files": [ + "lib/*.tsp", + "dist/**", + "!dist/test/**" + ], + "peerDependencies": { + "@typespec/compiler": "workspace:~" + }, + "devDependencies": { + "@types/node": "~18.11.19", + "@typespec/compiler": "workspace:~", + "@typespec/eslint-config-typespec": "workspace:~", + "@typespec/eslint-plugin": "workspace:~", + "@typespec/library-linter": "workspace:~", + "@typespec/tspd": "workspace:~", + "@vitest/coverage-v8": "^1.4.0", + "@vitest/ui": "^1.4.0", + "c8": "^9.1.0", + "eslint": "^8.57.0", + "rimraf": "~5.0.5", + "typescript": "~5.4.2", + "vitest": "^1.4.0" + } +} diff --git a/packages/xml/src/decorators.ts b/packages/xml/src/decorators.ts new file mode 100644 index 0000000000..46850e160d --- /dev/null +++ b/packages/xml/src/decorators.ts @@ -0,0 +1 @@ +export const namespace = "TypeSpec.Xml"; diff --git a/packages/xml/src/index.ts b/packages/xml/src/index.ts new file mode 100644 index 0000000000..5400dba186 --- /dev/null +++ b/packages/xml/src/index.ts @@ -0,0 +1 @@ +export * from "./decorators.js"; diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts new file mode 100644 index 0000000000..92c59f3108 --- /dev/null +++ b/packages/xml/src/lib.ts @@ -0,0 +1,7 @@ +import { createTypeSpecLibrary } from "@typespec/compiler"; + +export const libDef = { + name: "@typespec/xml", + diagnostics: {}, +} as const; +export const { reportDiagnostic, createStateSymbol } = createTypeSpecLibrary(libDef); diff --git a/packages/xml/src/testing/index.ts b/packages/xml/src/testing/index.ts new file mode 100644 index 0000000000..9d90035633 --- /dev/null +++ b/packages/xml/src/testing/index.ts @@ -0,0 +1,10 @@ +import { + createTestLibrary, + findTestPackageRoot, + TypeSpecTestLibrary, +} from "@typespec/compiler/testing"; + +export const XmlTestLibrary: TypeSpecTestLibrary = createTestLibrary({ + name: "@typespec/xml", + packageRoot: await findTestPackageRoot(import.meta.url), +}); diff --git a/packages/xml/test/decorators.test.ts b/packages/xml/test/decorators.test.ts new file mode 100644 index 0000000000..9642910e32 --- /dev/null +++ b/packages/xml/test/decorators.test.ts @@ -0,0 +1,3 @@ +import { it } from "vitest"; + +it("hello", () => {}); diff --git a/packages/xml/test/test-host.ts b/packages/xml/test/test-host.ts new file mode 100644 index 0000000000..37c6d98077 --- /dev/null +++ b/packages/xml/test/test-host.ts @@ -0,0 +1,12 @@ +import { createTestHost, createTestWrapper } from "@typespec/compiler/testing"; +import { XmlTestLibrary } from "../src/testing/index.js"; + +export async function createOpenAPITestHost() { + return createTestHost({ + libraries: [XmlTestLibrary], + }); +} +export async function createOpenAPITestRunner() { + const host = await createOpenAPITestHost(); + return createTestWrapper(host, { autoUsings: ["TypeSpec.Xml"] }); +} diff --git a/packages/xml/tsconfig.config.json b/packages/xml/tsconfig.config.json new file mode 100644 index 0000000000..79fb341f39 --- /dev/null +++ b/packages/xml/tsconfig.config.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": {} +} diff --git a/packages/xml/tsconfig.json b/packages/xml/tsconfig.json new file mode 100644 index 0000000000..b73ccb236b --- /dev/null +++ b/packages/xml/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "references": [{ "path": "../compiler/tsconfig.json" }, { "path": "../rest/tsconfig.json" }], + "compilerOptions": { + "outDir": "dist", + "rootDir": ".", + "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", + "lib": ["DOM", "ESNext"] + }, + "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] +} diff --git a/packages/xml/vitest.config.ts b/packages/xml/vitest.config.ts new file mode 100644 index 0000000000..15eeaceb85 --- /dev/null +++ b/packages/xml/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig, mergeConfig } from "vitest/config"; +import { defaultTypeSpecVitestConfig } from "../../vitest.workspace.js"; + +export default mergeConfig(defaultTypeSpecVitestConfig, defineConfig({})); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 578b138592..82189a342e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1517,6 +1517,48 @@ importers: specifier: ~5.4.2 version: 5.4.2 + packages/xml: + devDependencies: + '@types/node': + specifier: ~18.11.19 + version: 18.11.19 + '@typespec/compiler': + specifier: workspace:~ + version: link:../compiler + '@typespec/eslint-config-typespec': + specifier: workspace:~ + version: link:../eslint-config-typespec + '@typespec/eslint-plugin': + specifier: workspace:~ + version: link:../eslint-plugin-typespec + '@typespec/library-linter': + specifier: workspace:~ + version: link:../library-linter + '@typespec/tspd': + specifier: workspace:~ + version: link:../tspd + '@vitest/coverage-v8': + specifier: ^1.4.0 + version: 1.4.0(vitest@1.4.0) + '@vitest/ui': + specifier: ^1.4.0 + version: 1.4.0(vitest@1.4.0) + c8: + specifier: ^9.1.0 + version: 9.1.0 + eslint: + specifier: ^8.57.0 + version: 8.57.0 + rimraf: + specifier: ~5.0.5 + version: 5.0.5 + typescript: + specifier: ~5.4.2 + version: 5.4.2 + vitest: + specifier: ^1.4.0 + version: 1.4.0(@types/node@18.11.19)(@vitest/ui@1.4.0) + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -1918,14 +1960,14 @@ packages: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-compilation-targets@7.23.6: @@ -1992,26 +2034,26 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.23.9 - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 /@babel/helper-member-expression-to-functions@7.23.0: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} @@ -2030,7 +2072,7 @@ packages: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-plugin-utils@7.22.5: @@ -2071,14 +2113,14 @@ packages: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} @@ -2098,7 +2140,7 @@ packages: dependencies: '@babel/helper-function-name': 7.23.0 '@babel/template': 7.23.9 - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/helpers@7.24.0: @@ -2124,7 +2166,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 + dev: true /@babel/parser@7.24.0: resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} @@ -2842,7 +2885,7 @@ packages: '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: false /@babel/plugin-transform-react-pure-annotations@7.23.3(@babel/core@7.24.0): @@ -3099,7 +3142,7 @@ packages: dependencies: '@babel/core': 7.24.0 '@babel/helper-plugin-utils': 7.22.5 - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 esutils: 2.0.3 dev: false @@ -3163,8 +3206,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 /@babel/template@7.24.0: resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} @@ -3184,8 +3227,8 @@ packages: '@babel/helper-function-name': 7.23.0 '@babel/helper-hoist-variables': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -3717,7 +3760,7 @@ packages: react: ^18.0.0 react-dom: ^18.0.0 dependencies: - '@babel/parser': 7.23.9 + '@babel/parser': 7.24.0 '@babel/traverse': 7.23.9 '@docusaurus/logger': 3.1.1 '@docusaurus/utils': 3.1.1(@docusaurus/types@3.1.1)(@swc/core@1.4.8) @@ -6224,7 +6267,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} @@ -6238,7 +6281,7 @@ packages: resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -6254,7 +6297,6 @@ packages: dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -7490,7 +7532,7 @@ packages: resolution: {integrity: sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==} engines: {node: '>=10'} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 entities: 4.5.0 dev: false @@ -7610,6 +7652,7 @@ packages: /@swagger-api/apidom-ns-json-schema-draft-4@0.97.0: resolution: {integrity: sha512-eBMIPxX4huNDGle6TOfSe1kKS1/HvL6w66GWWLFxZW2doCQHMADgjo7j/kVowrXiJtEoMgjBVp3W30WkcwBVug==} + requiresBuild: true dependencies: '@babel/runtime-corejs3': 7.24.0 '@swagger-api/apidom-ast': 0.97.0 @@ -8121,8 +8164,8 @@ packages: /@types/babel__core@7.20.5: resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 @@ -8131,20 +8174,20 @@ packages: /@types/babel__generator@7.6.8: resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: true /@types/babel__template@7.4.4: resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} dependencies: - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 + '@babel/parser': 7.24.0 + '@babel/types': 7.24.0 dev: true /@types/babel__traverse@7.20.5: resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} dependencies: - '@babel/types': 7.23.9 + '@babel/types': 7.24.0 dev: true /@types/body-parser@1.19.5: @@ -18171,7 +18214,7 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.22 + '@jridgewell/trace-mapping': 0.3.25 '@swc/core': 1.4.8 jest-worker: 27.5.1 schema-utils: 3.3.0 diff --git a/tsconfig.ws.json b/tsconfig.ws.json index 06502f6d90..30ec9de387 100644 --- a/tsconfig.ws.json +++ b/tsconfig.ws.json @@ -19,7 +19,8 @@ { "path": "packages/tspd/tsconfig.json" }, { "path": "packages/samples/tsconfig.json" }, { "path": "packages/json-schema/tsconfig.json" }, - { "path": "packages/best-practices/tsconfig.json" } + { "path": "packages/best-practices/tsconfig.json" }, + { "path": "packages/xml/tsconfig.json" } ], "files": [] } From 92e6b20ae491071071a31e7c640874404d7b614f Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 09:46:58 -0700 Subject: [PATCH 02/35] Add xml decorators --- docs/libraries/xml/guide.md | 1064 +++++++++++++++++ packages/website/sidebars.ts | 1 + packages/xml/generated-defs/TypeSpec.Xml.ts | 168 +++ .../generated-defs/TypeSpec.Xml.ts-test.ts | 26 + packages/xml/lib/decorators.tsp | 169 +++ packages/xml/package.json | 1 + packages/xml/src/decorators.ts | 94 ++ packages/xml/src/lib.ts | 41 +- packages/xml/src/types.ts | 4 + packages/xml/test/decorators.test.ts | 156 ++- packages/xml/test/test-host.ts | 6 +- 11 files changed, 1720 insertions(+), 10 deletions(-) create mode 100644 docs/libraries/xml/guide.md create mode 100644 packages/xml/generated-defs/TypeSpec.Xml.ts create mode 100644 packages/xml/generated-defs/TypeSpec.Xml.ts-test.ts create mode 100644 packages/xml/src/types.ts diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md new file mode 100644 index 0000000000..f318fa19fa --- /dev/null +++ b/docs/libraries/xml/guide.md @@ -0,0 +1,1064 @@ +--- +title: Guide +--- + +# Xml Library + +## Examples + +### 1. Array of primitive types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 1.1:** + +- ❌ ItemsName +- ❌ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + @xml.unwrapped + tags: string[]; +} +``` + + + +```xml + + abc + def + +``` + + + +```yaml +Pet: + type: "object" + properties: + tags: + type: "array" + items: + type: string + xml: + name: "XmlPet" +``` + +
+ +**Scenario 1.2:** + +- ❌ ItemsName +- ✅ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + @encodedName("application/xml", "ItemsTags") + tags: string[]; +} +``` + + + +```xml + + + abc + def + + +``` + + + +```yaml +Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + wrapped: true + items: + type: string + xml: + name: "XmlPet" +``` + +
+ +**Scenario 1.3:** + +- ✅ ItemsName +- ❌ Wrapped + + + +```tsp +@encodedName("application/xml", "ItemsName") +scalar tag extends string; + +@encodedName("application/xml", "XmlPet") +model Pet { + @xml.unwrapped + tags: tag[]; +} +``` + + + +```xml + + abc + def + +``` + + + +```yaml +Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + items: + type: string + xml: + name: ItemsName + xml: + name: "XmlPet" +``` + +
+ +**Scenario 1.4:** + +- ✅ ItemsName +- ✅ Wrapped + + + +```tsp +@encodedName("application/xml", "ItemsName") +scalar tag extends string; + +@encodedName("application/xml", "XmlPet") +model Pet { + @encodedName("application/xml", "ItemsTags") + tags: tag[]; +} +``` + + + +```xml + + + abc + def + + +``` + + + +```yaml +Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + wrapped: true + items: + type: string + xml: + name: ItemsName + xml: + name: "XmlPet" +``` + +
+ +### 2. Complex array types + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 2.1:** + +- ❌ ItemsName +- ❌ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + @xml.unwrapped + tags: Tag[]; +} + +@encodedName("application/xml", "XmlTag") +model Tag { + name: string; +} +``` + + + +```xml + + + string + + +``` + + + +```yaml +Tag: + type: "object" + properties: + name: + type: "string" + xml: + name: "XmlTag" +Pet: + type: "object" + properties: + tags: + type: "array" + items: + $ref: "#/definitions/Tag" + xml: + name: "XmlPet" +``` + +
+ +**Scenario 2.2:** + +- ❌ ItemsName +- ✅ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + tags: Tag[]; +} + +@encodedName("application/xml", "XmlTag") +model Tag { + name: string; +} +``` + + + +```xml + + + + string + + + +``` + + + +```yaml +Tag: + type: "object" + properties: + name: + type: "string" + xml: + name: "XmlTag" +Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + wrapped: true + items: + $ref: "#/definitions/Tag" + xml: + name: "XmlPet" +``` + +
+ +**Scenario 2.3:** + +- ✅ ItemsName +- ❌ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + @encodedName("application/xml", "ItemsTags") + @xml.unwrapped + tags: Tag[]; +} + +@encodedName("application/xml", "XmlTag") +model Tag { + name: string; +} +``` + + + +```xml + + + string + + +``` + + + +```yaml +Tag: + type: "object" + properties: + name: + type: "string" + xml: + name: "XmlTag" + Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + items: + $ref: "#/definitions/Tag" + xml: + name: ItemsXMLName + xml: + name: "XmlPet" +``` + +
+ +**Scenario 2.4:** + +- ✅ ItemsName +- ✅ Wrapped + + + +```tsp +@encodedName("application/xml", "XmlPet") +model Pet { + @encodedName("application/xml", "ItemsTags") + tags: Tag[]; +} + +@encodedName("application/xml", "XmlTag") +model Tag { + name: string; +} +``` + + + +```xml + + + + string + + + +``` + + + +```yaml +Tag: + type: "object" + properties: + name: + type: "string" +Pet: + type: "object" + properties: + tags: + type: "array" + xml: + name: "ItemsTags" + wrapped: true + items: + $ref: "#/definitions/Tag" + xml: + name: "XmlPet" +``` + +
+ +### 3. Nested models + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 3.1:** + +No annotations + + + +```tsp +model Book { + author: Author; +} + +model Author { + name: string; +} +``` + + + +```xml + + + string + + +``` + + + +```yaml +Book: + type: object + properties: + author: + $ref: "#/components/schemas/Author" +Author: + type: object + properties: + name: + type: string +``` + +
+ +**Scenario 3.2:** + +Nested model has xml encoded name. + +_⚠️ no op in serialization of Book_ + + + +```tsp +model Book { + author: Author; +} + +@encodedName("application/xml", "XmlAuthor") +model Author { + name: string; +} +``` + + + +```xml + + + string + + +``` + + + +```yaml +Book: + type: object + properties: + author: + allOf: + - $ref: "#/components/schemas/Author" + xml: + name: "author" # Here we have to redefine this name otherwise in OpenAPI semantic the `XmlAuthor` name would be used +Author: + type: object + properties: + name: + type: string + xml: + name: "XmlAuthor" +``` + +
+ +**Scenario 3.2:** + +Property has encoded name + + + +```tsp +model Book { + @encodedName("application/xml", "xml-author") + author: Author; +} + +model Author { + name: string; +} +``` + + + +```xml + + + string + + +``` + + + +```yaml +Book: + type: object + properties: + author: + allOf: + - $ref: "#/components/schemas/Author" + xml: + name: "xml-author" +Author: + type: object + properties: + name: + type: string +``` + +
+ +### 4. Attributes + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 4.1:** + +Convert a property to an attribute + + + +```tsp +model Book { + @Xml.attribute + id: string; + + title: string; + author: string; +} +``` + + + +```xml + + string + string + +``` + + + +```yaml +Book: + type: object + properties: + id: + type: integer + title: + type: string + xml: + name: "xml-title" + author: + type: string +``` + +
+ +### 5. Namespace and prefix (inline form) + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 5.1:** + +On model + + + +```tsp +@Xml.ns("smp", "http://example.com/schema") +model Book { + id: string; + title: string; + author: string; +} +``` + + + +```xml + + 0 + string + string + +``` + + + +```yaml +Book: + type: object + properties: + id: + type: integer + title: + type: string + author: + type: string + xml: + prefix: "smp" + namespace: "http://example.com/schema" +``` + +
+ +**Scenario 5.2:** + +On model and properties + + + +```tsp +@Xml.ns("smp", "http://example.com/schema") +model Book { + id: string; + + @Xml.ns("smp", "http://example.com/schema") + title: string; + + @Xml.ns("ns2", "http://example.com/ns2") + author: string; +} +``` + + + +```xml + + 0 + string + string + +``` + + + +```yaml +Book: + type: object + properties: + id: + type: integer + title: + type: string + xml: + prefix: "smp" + namespace: "http://example.com/schema" + author: + type: string + xml: + prefix: "ns2" + namespace: "http://example.com/ns2" + xml: + prefix: "smp" + namespace: "http://example.com/schema" +``` + +
+ +### 6. Namespace and prefix (normalized form) + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 6.1:** + +On model + + + +```tsp +@Xml.nsDeclarations +enum Namespaces { + smp: "http://example.com/schema", +} + +@Xml.ns(Namespaces.smp) +model Book { + id: string; + title: string; + author: string; +} +``` + + + +```xml + + 0 + string + string + +``` + + + +```yaml +Book: + type: object + properties: + id: + type: integer + title: + type: string + author: + type: string + xml: + prefix: "smp" + namespace: "http://example.com/schema" +``` + +
+ +**Scenario 6.2:** + +On model and properties + + + +```tsp +@Xml.nsDeclarations +enum Namespaces { + smp: "http://example.com/schema", + ns2: "http://example.com/ns2", +} + +@Xml.ns(Namespaces.smp) +model Book { + id: string; + + @Xml.ns(Namespaces.smp) + title: string; + + @Xml.ns(Namespaces.ns2) + author: string; +} +``` + + + +```xml + + 0 + string + string + +``` + + + +```yaml +Book: + type: object + properties: + id: + type: integer + title: + type: string + xml: + prefix: "smp" + namespace: "http://example.com/schema" + author: + type: string + xml: + prefix: "ns2" + namespace: "http://example.com/ns2" + xml: + prefix: "smp" + namespace: "http://example.com/schema" +``` + +
+ +### 6. Property setting the text of the node + + + + + + + + + + + + + + + + + + +
ScenarioTypeSpecXmlOpenAPI3
+ +**Scenario 6.1:** + + + +```tsp +model BlobName { + @Xml.attribute language: string; + @Xml.unwrapped content: string; +} +``` + + + +```xml + + ...content... + +``` + + + +```yaml +Book: + type: object + properties: + language: + type: string + content: + type: string + xml: + x-ms-text: true # on autorest emitter +``` + +
diff --git a/packages/website/sidebars.ts b/packages/website/sidebars.ts index c59041518e..c039f1d332 100644 --- a/packages/website/sidebars.ts +++ b/packages/website/sidebars.ts @@ -140,6 +140,7 @@ const sidebars: SidebarsConfig = { createLibraryReferenceStructure("versioning", "Versioning", false, [ "libraries/versioning/guide", ]), + createLibraryReferenceStructure("xml", "Xml", false, ["libraries/xml/guide"]), ], }, { diff --git a/packages/xml/generated-defs/TypeSpec.Xml.ts b/packages/xml/generated-defs/TypeSpec.Xml.ts new file mode 100644 index 0000000000..c84ece94ce --- /dev/null +++ b/packages/xml/generated-defs/TypeSpec.Xml.ts @@ -0,0 +1,168 @@ +import type { DecoratorContext, Enum, ModelProperty, Type } from "@typespec/compiler"; + +/** + * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + * + * @example + * ```tsp + * @name("XmlBook") + * model Book { + * @name("XmlId") id: string; + * @encodedName("application/xml", "XmlName") name: string; + * content: string; + * } + * ``` + * + * ```xml + * + * string + * string + * string + * + * ``` + */ +export type NameDecorator = (context: DecoratorContext, target: Type, name: string) => void; + +/** + * Specify that the target property should be encoded as an XML attribute instead of node. + * + * @example Default + * + * ```tsp + * model Blob { + * id: string; + * } + * ``` + * + * ```xml + * + * abcdef + * + * ``` + * @example With `@attribute` + * + * ```tsp + * model Blob { + * @attribute id: string; + * } + * ``` + * + * ```xml + * + * + * ``` + */ +export type AttributeDecorator = (context: DecoratorContext, target: ModelProperty) => void; + +/** + * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. + * It cannot be used with `@attribute`. + * + * @example Array property default + * + * ```tsp + * model Pet { + * tags: Tag[]; + * } + * ``` + * + * ```xml + * + * + * + * string + * + * + * + * ``` + * @example Array property with `@unwrapped` + * + * ```tsp + * model Pet { + * @unwrapped tags: Tag[]; + * } + * ``` + * + * ```xml + * + * + * string + * + * + * ``` + * @example String property default + * + * ```tsp + * model BlobName { + * content: string; + * } + * ``` + * + * ```xml + * + * + * abcdef + * + * + * ``` + * @example Array property with `@unwrapped` + * + * ```tsp + * model BlobName { + * @unwrapped content: string; + * } + * ``` + * + * ```xml + * + * abcdef + * + * ``` + */ +export type UnwrappedDecorator = (context: DecoratorContext, target: ModelProperty) => void; + +/** + * Specify the XML namespace for this element. It can be used in 2 different ways: + * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element + * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + * + * @example With strings + * + * ```tsp + * @ns( "https://example.com/ns1", "ns1") + * model Foo { + * @ns("https://example.com/ns1", "ns1") + * bar: string + * @ns("https://example.com/ns2", "ns2") + * bar: string + * } + * ``` + * @example With enum + * + * ```tsp + * @Xml.nsDeclarations + * enum Namespaces { + * ns1: "https://example.com/ns1", + * ns2: "https://example.com/ns2" + * } + * + * @Xml.ns(Namespaces.ns1) + * model Foo { + * @Xml.ns(Namespaces.ns1) + * bar: string + * @Xml.ns(Namespaces.ns2) + * bar: string + * } + * ``` + */ +export type NsDecorator = ( + context: DecoratorContext, + target: Type, + ns: Type, + prefix?: string +) => void; + +/** + * Mark an enum as declaring XML namespaces. See `@ns` + */ +export type NsDeclarationsDecorator = (context: DecoratorContext, target: Enum) => void; diff --git a/packages/xml/generated-defs/TypeSpec.Xml.ts-test.ts b/packages/xml/generated-defs/TypeSpec.Xml.ts-test.ts new file mode 100644 index 0000000000..f4648c5e89 --- /dev/null +++ b/packages/xml/generated-defs/TypeSpec.Xml.ts-test.ts @@ -0,0 +1,26 @@ +/** An error here would mean that the decorator is not exported or doesn't have the right name. */ +import { $attribute, $name, $ns, $nsDeclarations, $unwrapped } from "@typespec/xml"; +import { + AttributeDecorator, + NameDecorator, + NsDeclarationsDecorator, + NsDecorator, + UnwrappedDecorator, +} from "./TypeSpec.Xml.js"; + +type Decorators = { + $name: NameDecorator; + $attribute: AttributeDecorator; + $unwrapped: UnwrappedDecorator; + $ns: NsDecorator; + $nsDeclarations: NsDeclarationsDecorator; +}; + +/** An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ... */ +const _: Decorators = { + $name, + $attribute, + $unwrapped, + $ns, + $nsDeclarations, +}; diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index bd0fbf6177..2676143f3d 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -1,3 +1,172 @@ using TypeSpec.Reflection; namespace TypeSpec.Xml; + +/** + * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + * + * @example + * + * ```tsp + * @name("XmlBook") + * model Book { + * @name("XmlId") id: string; + * @encodedName("application/xml", "XmlName") name: string; + * content: string; + * } + * ``` + * + * ```xml + * + * string + * string + * string + * + * ``` + */ +extern dec name(target: unknown, name: valueof string); + +/** + * Specify that the target property should be encoded as an XML attribute instead of node. + * + * @example Default + * + * ```tsp + * model Blob { + * id: string; + * } + * ``` + * + * ```xml + * + * abcdef + * + * ``` + * + * @example With `@attribute` + * + * ```tsp + * model Blob { + * @attribute id: string; + * } + * ``` + * + * ```xml + * + * + * ``` + */ +extern dec attribute(target: ModelProperty); + +/** + * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. + * It cannot be used with `@attribute`. + * + * @example Array property default + * + * ```tsp + * model Pet { + * tags: Tag[]; + * } + * ``` + * + * ```xml + * + * + * + * string + * + * + * + * ``` + * + * @example Array property with `@unwrapped` + * + * ```tsp + * model Pet { + * @unwrapped tags: Tag[]; + * } + * ``` + * + * ```xml + * + * + * string + * + * + * ``` + * + * @example String property default + * + * ```tsp + * model BlobName { + * content: string; + * } + * ``` + * + * ```xml + * + * + * abcdef + * + * + * ``` + * + * @example Array property with `@unwrapped` + * + * ```tsp + * model BlobName { + * @unwrapped content: string; + * } + * ``` + * + * ```xml + * + * abcdef + * + * ``` + */ +extern dec unwrapped(target: ModelProperty); + +/** + * Specify the XML namespace for this element. It can be used in 2 different ways: + * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element + * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + * + * @example With strings + * + * ```tsp + * @ns( "https://example.com/ns1", "ns1") + * model Foo { + * @ns("https://example.com/ns1", "ns1") + * bar: string + * @ns("https://example.com/ns2", "ns2") + * bar: string + * } + * ``` + * + * @example With enum + * + * ```tsp + * @Xml.nsDeclarations + * enum Namespaces { + * ns1: "https://example.com/ns1", + * ns2: "https://example.com/ns2" + * } + * + * @Xml.ns(Namespaces.ns1) + * model Foo { + * @Xml.ns(Namespaces.ns1) + * bar: string + * @Xml.ns(Namespaces.ns2) + * bar: string + * } + * ``` + * + */ +extern dec ns(target: unknown, ns: string | EnumMember, prefix?: valueof string); + +/** + * Mark an enum as declaring XML namespaces. See `@ns` + */ +extern dec nsDeclarations(target: Enum); diff --git a/packages/xml/package.json b/packages/xml/package.json index f2e023efe0..615755ae8f 100644 --- a/packages/xml/package.json +++ b/packages/xml/package.json @@ -33,6 +33,7 @@ "gen-extern-signature": "tspd --enable-experimental gen-extern-signature .", "lint-typespec-library": "tsp compile . --warn-as-error --import @typespec/library-linter --no-emit", "test": "vitest run", + "test:watch": "vitest -w", "test:ui": "vitest --ui", "test-official": "vitest run --coverage --reporter=junit --reporter=default --no-file-parallelism", "lint": "eslint . --ext .ts --max-warnings=0", diff --git a/packages/xml/src/decorators.ts b/packages/xml/src/decorators.ts index 46850e160d..ba0989fbd2 100644 --- a/packages/xml/src/decorators.ts +++ b/packages/xml/src/decorators.ts @@ -1 +1,95 @@ +import { + $encodedName, + DecoratorContext, + Enum, + ModelProperty, + Program, + Type, +} from "@typespec/compiler"; +import { + AttributeDecorator, + NameDecorator, + NsDeclarationsDecorator, + NsDecorator, + UnwrappedDecorator, +} from "../generated-defs/TypeSpec.Xml.js"; +import { XmlStateKeys, reportDiagnostic } from "./lib.js"; +import { XmlNamespace } from "./types.js"; + export const namespace = "TypeSpec.Xml"; + +export const $name: NameDecorator = (context, target, name) => { + context.call($encodedName, target, "application/xml", name); +}; + +export const $attribute: AttributeDecorator = (context, target) => { + context.program.stateSet(XmlStateKeys.attribute).add(target); +}; + +export function isAttribute(program: Program, target: ModelProperty): boolean { + return program.stateSet(XmlStateKeys.attribute).has(target); +} + +export const $unwrapped: UnwrappedDecorator = (context, target) => { + context.program.stateSet(XmlStateKeys.unwrapped).add(target); +}; + +export function isUnwrapped(program: Program, target: ModelProperty): boolean { + return program.stateSet(XmlStateKeys.unwrapped).has(target); +} + +export const $nsDeclarations: NsDeclarationsDecorator = (context, target) => { + context.program.stateSet(XmlStateKeys.nsDeclaration).add(target); +}; + +function isNsDeclarationsEnum(program: Program, target: Enum): boolean { + return program.stateSet(XmlStateKeys.nsDeclaration).has(target); +} + +export const $ns: NsDecorator = (context, target, namespace: Type, prefix?: string) => { + const data = getData(context, namespace, prefix); + if (data) { + context.program.stateMap(XmlStateKeys.nsDeclaration).set(target, data); + } +}; + +export function getNs(program: Program, target: Type): XmlNamespace | undefined { + return program.stateMap(XmlStateKeys.nsDeclaration).get(target); +} + +function getData( + context: DecoratorContext, + namespace: Type, + prefix?: string +): XmlNamespace | undefined { + switch (namespace.kind) { + case "String": + if (!prefix) { + reportDiagnostic(context.program, { + code: "ns-missing-prefix", + target: context.decoratorTarget, + }); + return undefined; + } + return { namespace: namespace.value, prefix }; + case "EnumMember": + if (!isNsDeclarationsEnum(context.program, namespace.enum)) { + reportDiagnostic(context.program, { + code: "ns-enum-not-declaration", + target: context.decoratorTarget, + }); + return undefined; + } + if (typeof namespace.value !== "string") { + reportDiagnostic(context.program, { + code: "invalid-ns-declaration-member", + target: context.decoratorTarget, + format: { name: namespace.name }, + }); + return undefined; + } + return { namespace: namespace.value, prefix: namespace.name }; + default: + return undefined; + } +} diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts index 92c59f3108..cd076fdc97 100644 --- a/packages/xml/src/lib.ts +++ b/packages/xml/src/lib.ts @@ -1,7 +1,38 @@ -import { createTypeSpecLibrary } from "@typespec/compiler"; +import { createTypeSpecLibrary, paramMessage } from "@typespec/compiler"; -export const libDef = { +export const { + reportDiagnostic, + createStateSymbol, + stateKeys: XmlStateKeys, +} = createTypeSpecLibrary({ name: "@typespec/xml", - diagnostics: {}, -} as const; -export const { reportDiagnostic, createStateSymbol } = createTypeSpecLibrary(libDef); + diagnostics: { + "ns-enum-not-declaration": { + severity: "error", + messages: { + default: + "Enum member used as namespace must be part of an enum marked with @nsDeclaration.", + }, + }, + "invalid-ns-declaration-member": { + severity: "error", + messages: { + default: paramMessage`Enum member ${"name"} must have a value that is the XML namespace url.`, + }, + }, + "ns-missing-prefix": { + severity: "error", + messages: { + default: "When using a string namespace you must provide a prefix as the 2nd argument.", + }, + }, + }, + state: { + attribute: { description: "Mark a model property as to be serialized as xml attribute" }, + unwrapped: { + description: "Mark a model property as to be serialized without a node wrapping the content.", + }, + ns: { description: "Namespace data" }, + nsDeclaration: { description: "Mark an enum as declarting Xml Namespaces" }, + }, +} as const); diff --git a/packages/xml/src/types.ts b/packages/xml/src/types.ts new file mode 100644 index 0000000000..c37d08184e --- /dev/null +++ b/packages/xml/src/types.ts @@ -0,0 +1,4 @@ +export interface XmlNamespace { + readonly namespace: string; + readonly prefix: string; +} diff --git a/packages/xml/test/decorators.test.ts b/packages/xml/test/decorators.test.ts index 9642910e32..9c22baaca1 100644 --- a/packages/xml/test/decorators.test.ts +++ b/packages/xml/test/decorators.test.ts @@ -1,3 +1,155 @@ -import { it } from "vitest"; +import { Model, ModelProperty, resolveEncodedName } from "@typespec/compiler"; +import { BasicTestRunner, expectDiagnostics } from "@typespec/compiler/testing"; +import { beforeEach, describe, expect, it } from "vitest"; +import { getNs, isAttribute, isUnwrapped } from "../src/decorators.js"; +import { createXmlTestRunner } from "./test-host.js"; -it("hello", () => {}); +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createXmlTestRunner(); +}); + +describe("@name", () => { + it("set the value via encodedName", async () => { + const { Blob } = (await runner.compile(`@test @Xml.name("XmlBlob") model Blob {}`)) as { + Blob: Model; + }; + + expect(resolveEncodedName(runner.program, Blob, "application/xml")).toEqual("XmlBlob"); + }); +}); + +describe("@attribute", () => { + it("mark property as being an attribute", async () => { + const { id } = (await runner.compile(`model Blob { + @test @Xml.attribute id : string + }`)) as { id: ModelProperty }; + + expect(isAttribute(runner.program, id)).toBe(true); + }); + + it("returns false if property is not decorated", async () => { + const { id } = (await runner.compile(`model Blob { + @test id : string + }`)) as { id: ModelProperty }; + + expect(isAttribute(runner.program, id)).toBe(false); + }); +}); + +describe("@unwrapped", () => { + it("mark property as to not be wrapped", async () => { + const { id } = (await runner.compile(`model Blob { + @test @Xml.unwrapped id : string + }`)) as { id: ModelProperty }; + + expect(isUnwrapped(runner.program, id)).toBe(true); + }); + + it("returns false if property is not decorated", async () => { + const { id } = (await runner.compile(`model Blob { + @test id : string + }`)) as { id: ModelProperty }; + + expect(isUnwrapped(runner.program, id)).toBe(false); + }); +}); + +describe("@ns", () => { + it("provide the namespace and prefix using string", async () => { + const { id } = await runner.compile(` + model Blob { + @test @Xml.ns("https://example.com/ns1", "ns1") id : string; + } + `); + + expect(getNs(runner.program, id)).toEqual({ + namespace: "https://example.com/ns1", + prefix: "ns1", + }); + }); + + it("doesn't carry over to children", async () => { + const { id } = await runner.compile(` + @Xml.ns("https://example.com/ns1", "ns1") + model Blob { + @test id : string; + } + `); + + expect(getNs(runner.program, id)).toBeUndefined(); + }); + + it("provide the namespace using enum declaration", async () => { + const { id } = await runner.compile(` + @Xml.nsDeclarations + enum Namespaces { + ns1: "https://example.com/ns1", + ns2: "https://example.com/ns2" + } + + model Blob { + @test @Xml.ns(Namespaces.ns2) id : string; + } + `); + + expect(getNs(runner.program, id)).toEqual({ + namespace: "https://example.com/ns2", + prefix: "ns2", + }); + }); + + it("emit warning if target enum is missing @nsDeclarations decorator", async () => { + const diagnostics = await runner.diagnose(` + enum Namespaces { + ns1: "https://example.com/ns1", + } + + model Blob { + @Xml.ns(Namespaces.ns1) id : string; + } + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/xml/ns-enum-not-declaration", + message: "Enum member used as namespace must be part of an enum marked with @nsDeclaration.", + }); + }); + + it("emit warning if target enum member is missing a value", async () => { + const diagnostics = await runner.diagnose(` + @Xml.nsDeclarations + enum Namespaces { + ns1 + } + + model Blob { + @Xml.ns(Namespaces.ns1) id : string; + } + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/xml/invalid-ns-declaration-member", + message: "Enum member ns1 must have a value that is the XML namespace url.", + }); + }); + + it("emit warning if target enum member value is a number", async () => { + const diagnostics = await runner.diagnose(` + @Xml.nsDeclarations + enum Namespaces { + ns1: 1 + } + + model Blob { + @Xml.ns(Namespaces.ns1) id : string; + } + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/xml/invalid-ns-declaration-member", + message: "Enum member ns1 must have a value that is the XML namespace url.", + }); + }); +}); diff --git a/packages/xml/test/test-host.ts b/packages/xml/test/test-host.ts index 37c6d98077..ada33dbc4c 100644 --- a/packages/xml/test/test-host.ts +++ b/packages/xml/test/test-host.ts @@ -1,12 +1,12 @@ import { createTestHost, createTestWrapper } from "@typespec/compiler/testing"; import { XmlTestLibrary } from "../src/testing/index.js"; -export async function createOpenAPITestHost() { +export async function createXmlTestHost() { return createTestHost({ libraries: [XmlTestLibrary], }); } -export async function createOpenAPITestRunner() { - const host = await createOpenAPITestHost(); +export async function createXmlTestRunner() { + const host = await createXmlTestHost(); return createTestWrapper(host, { autoUsings: ["TypeSpec.Xml"] }); } From 219afe582cb0580adb5e87b6d92a1a03a03ec4bc Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 09:54:09 -0700 Subject: [PATCH 03/35] Tweaks --- packages/xml/src/index.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/xml/src/index.ts b/packages/xml/src/index.ts index 5400dba186..48287a408a 100644 --- a/packages/xml/src/index.ts +++ b/packages/xml/src/index.ts @@ -1 +1,11 @@ -export * from "./decorators.js"; +export { + $attribute, + $name, + $ns, + $nsDeclarations, + $unwrapped, + getNs, + isAttribute, + isUnwrapped, +} from "./decorators.js"; +export type { XmlNamespace } from "./types.js"; From 475cf8ece6d7c78a19784650a2d82897dd7bdbda Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 09:54:29 -0700 Subject: [PATCH 04/35] Create feature-xml-2024-2-20-16-48-57.md --- .chronus/changes/feature-xml-2024-2-20-16-48-57.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/feature-xml-2024-2-20-16-48-57.md diff --git a/.chronus/changes/feature-xml-2024-2-20-16-48-57.md b/.chronus/changes/feature-xml-2024-2-20-16-48-57.md new file mode 100644 index 0000000000..a5a0085727 --- /dev/null +++ b/.chronus/changes/feature-xml-2024-2-20-16-48-57.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: internal +packages: + - "@typespec/xml" +--- + +Initial release of xml library From 10deac0c7b3b3596bd105693c139bc2e7dbd4d80 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 10:03:39 -0700 Subject: [PATCH 05/35] fix --- packages/xml/lib/decorators.tsp | 2 ++ packages/xml/lib/main.tsp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 2676143f3d..396015ef19 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -1,3 +1,5 @@ +import "../dist/src/decorators.js"; + using TypeSpec.Reflection; namespace TypeSpec.Xml; diff --git a/packages/xml/lib/main.tsp b/packages/xml/lib/main.tsp index 9847aa0002..29ee772dd0 100644 --- a/packages/xml/lib/main.tsp +++ b/packages/xml/lib/main.tsp @@ -1,2 +1 @@ -import "../dist/src/index.js"; import "./decorators.tsp"; From e3ec8420c42e201ffffe3438078fc615124a29b7 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 13:07:05 -0700 Subject: [PATCH 06/35] More validation and regen docs --- docs/libraries/xml/reference/decorators.md | 246 ++++++++++++++++++++ docs/libraries/xml/reference/index.mdx | 8 + packages/xml/README.md | 247 +++++++++++++++++++++ packages/xml/lib/decorators.tsp | 5 + packages/xml/src/decorators.ts | 25 ++- packages/xml/src/lib.ts | 12 + packages/xml/test/decorators.test.ts | 31 +++ 7 files changed, 573 insertions(+), 1 deletion(-) create mode 100644 docs/libraries/xml/reference/decorators.md diff --git a/docs/libraries/xml/reference/decorators.md b/docs/libraries/xml/reference/decorators.md new file mode 100644 index 0000000000..1127436ff6 --- /dev/null +++ b/docs/libraries/xml/reference/decorators.md @@ -0,0 +1,246 @@ +--- +title: "Decorators" +toc_min_heading_level: 2 +toc_max_heading_level: 3 +--- + +# Decorators + +## TypeSpec.Xml + +### `@attribute` {#@TypeSpec.Xml.attribute} + +Specify that the target property should be encoded as an XML attribute instead of node. + +```typespec +@TypeSpec.Xml.attribute +``` + +#### Target + +`ModelProperty` + +#### Parameters + +None + +#### Examples + +##### Default + +```tsp +model Blob { + id: string; +} +``` + +```xml + +abcdef + +``` + +##### With `@attribute` + +```tsp +model Blob { + @attribute id: string; +} +``` + +```xml + + +``` + +### `@name` {#@TypeSpec.Xml.name} + +Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + +```typespec +@TypeSpec.Xml.name(name: valueof string) +``` + +#### Target + +`unknown` + +#### Parameters + +| Name | Type | Description | +| ---- | ---------------- | ----------- | +| name | `valueof string` | | + +#### Examples + +```tsp +@name("XmlBook") +model Book { + @name("XmlId") id: string; + @encodedName("application/xml", "XmlName") name: string; + content: string; +} +``` + +```xml + +string +string +string + +``` + +### `@ns` {#@TypeSpec.Xml.ns} + +Specify the XML namespace for this element. It can be used in 2 different ways: + +1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element +2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + +```typespec +@TypeSpec.Xml.ns(ns: string | EnumMember, prefix?: valueof string) +``` + +#### Target + +`unknown` + +#### Parameters + +| Name | Type | Description | +| ------ | ---------------------- | ----------- | +| ns | `string \| EnumMember` | | +| prefix | `valueof string` | | + +#### Examples + +##### With strings + +```tsp +@ns("https://example.com/ns1", "ns1") +model Foo { + @ns("https://example.com/ns1", "ns1") + bar: string; + + @ns("https://example.com/ns2", "ns2") + bar: string; +} +``` + +##### With enum + +```tsp +@Xml.nsDeclarations +enum Namespaces { + ns1: "https://example.com/ns1", + ns2: "https://example.com/ns2", +} + +@Xml.ns(Namespaces.ns1) +model Foo { + @Xml.ns(Namespaces.ns1) + bar: string; + + @Xml.ns(Namespaces.ns2) + bar: string; +} +``` + +### `@nsDeclarations` {#@TypeSpec.Xml.nsDeclarations} + +Mark an enum as declaring XML namespaces. See `@ns` + +```typespec +@TypeSpec.Xml.nsDeclarations +``` + +#### Target + +`Enum` + +#### Parameters + +None + +### `@unwrapped` {#@TypeSpec.Xml.unwrapped} + +Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. +It cannot be used with `@attribute`. + +```typespec +@TypeSpec.Xml.unwrapped +``` + +#### Target + +`ModelProperty` + +#### Parameters + +None + +#### Examples + +##### Array property default + +```tsp +model Pet { + tags: Tag[]; +} +``` + +```xml + + + +string + + + +``` + +##### Array property with `@unwrapped` + +```tsp +model Pet { + @unwrapped tags: Tag[]; +} +``` + +```xml + + +string + + +``` + +##### String property default + +```tsp +model BlobName { + content: string; +} +``` + +```xml + + +abcdef + + +``` + +##### Array property with `@unwrapped` + +```tsp +model BlobName { + @unwrapped content: string; +} +``` + +```xml + +abcdef + +``` diff --git a/docs/libraries/xml/reference/index.mdx b/docs/libraries/xml/reference/index.mdx index 1beec4911f..6b1f7600a9 100644 --- a/docs/libraries/xml/reference/index.mdx +++ b/docs/libraries/xml/reference/index.mdx @@ -32,3 +32,11 @@ npm install --save-peer @typespec/xml ## TypeSpec.Xml + +### Decorators + +- [`@attribute`](./decorators.md#@TypeSpec.Xml.attribute) +- [`@name`](./decorators.md#@TypeSpec.Xml.name) +- [`@ns`](./decorators.md#@TypeSpec.Xml.ns) +- [`@nsDeclarations`](./decorators.md#@TypeSpec.Xml.nsDeclarations) +- [`@unwrapped`](./decorators.md#@TypeSpec.Xml.unwrapped) diff --git a/packages/xml/README.md b/packages/xml/README.md index da68f38cab..3119558c0e 100644 --- a/packages/xml/README.md +++ b/packages/xml/README.md @@ -7,3 +7,250 @@ TypeSpec library providing xml bindings ```bash npm install @typespec/xml ``` + +## Decorators + +### TypeSpec.Xml + +- [`@attribute`](#@attribute) +- [`@name`](#@name) +- [`@ns`](#@ns) +- [`@nsDeclarations`](#@nsdeclarations) +- [`@unwrapped`](#@unwrapped) + +#### `@attribute` + +Specify that the target property should be encoded as an XML attribute instead of node. + +```typespec +@TypeSpec.Xml.attribute +``` + +##### Target + +`ModelProperty` + +##### Parameters + +None + +##### Examples + +###### Default + +```tsp +model Blob { + id: string; +} +``` + +```xml + +abcdef + +``` + +###### With `@attribute` + +```tsp +model Blob { + @attribute id: string; +} +``` + +```xml + + +``` + +#### `@name` + +Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + +```typespec +@TypeSpec.Xml.name(name: valueof string) +``` + +##### Target + +`unknown` + +##### Parameters + +| Name | Type | Description | +| ---- | ---------------- | ----------- | +| name | `valueof string` | | + +##### Examples + +```tsp +@name("XmlBook") +model Book { + @name("XmlId") id: string; + @encodedName("application/xml", "XmlName") name: string; + content: string; +} +``` + +```xml + +string +string +string + +``` + +#### `@ns` + +Specify the XML namespace for this element. It can be used in 2 different ways: + +1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element +2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + +```typespec +@TypeSpec.Xml.ns(ns: string | EnumMember, prefix?: valueof string) +``` + +##### Target + +`unknown` + +##### Parameters + +| Name | Type | Description | +| ------ | ---------------------- | ----------- | +| ns | `string \| EnumMember` | | +| prefix | `valueof string` | | + +##### Examples + +###### With strings + +```tsp +@ns("https://example.com/ns1", "ns1") +model Foo { + @ns("https://example.com/ns1", "ns1") + bar: string; + + @ns("https://example.com/ns2", "ns2") + bar: string; +} +``` + +###### With enum + +```tsp +@Xml.nsDeclarations +enum Namespaces { + ns1: "https://example.com/ns1", + ns2: "https://example.com/ns2", +} + +@Xml.ns(Namespaces.ns1) +model Foo { + @Xml.ns(Namespaces.ns1) + bar: string; + + @Xml.ns(Namespaces.ns2) + bar: string; +} +``` + +#### `@nsDeclarations` + +Mark an enum as declaring XML namespaces. See `@ns` + +```typespec +@TypeSpec.Xml.nsDeclarations +``` + +##### Target + +`Enum` + +##### Parameters + +None + +#### `@unwrapped` + +Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. +It cannot be used with `@attribute`. + +```typespec +@TypeSpec.Xml.unwrapped +``` + +##### Target + +`ModelProperty` + +##### Parameters + +None + +##### Examples + +###### Array property default + +```tsp +model Pet { + tags: Tag[]; +} +``` + +```xml + + + +string + + + +``` + +###### Array property with `@unwrapped` + +```tsp +model Pet { + @unwrapped tags: Tag[]; +} +``` + +```xml + + +string + + +``` + +###### String property default + +```tsp +model BlobName { + content: string; +} +``` + +```xml + + +abcdef + + +``` + +###### Array property with `@unwrapped` + +```tsp +model BlobName { + @unwrapped content: string; +} +``` + +```xml + +abcdef + +``` diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 396015ef19..160038f877 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -7,6 +7,8 @@ namespace TypeSpec.Xml; /** * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` * + * @param name The name of the XML element or attribute + * * @example * * ```tsp @@ -135,6 +137,9 @@ extern dec unwrapped(target: ModelProperty); * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` * + * @param ns Provide the namespace URI or the enum member where it is defined. + * @param prefix Provide the name prefix if the namespace parameter was provided as a string. + * * @example With strings * * ```tsp diff --git a/packages/xml/src/decorators.ts b/packages/xml/src/decorators.ts index ba0989fbd2..e93dd2ed4e 100644 --- a/packages/xml/src/decorators.ts +++ b/packages/xml/src/decorators.ts @@ -49,7 +49,9 @@ function isNsDeclarationsEnum(program: Program, target: Enum): boolean { export const $ns: NsDecorator = (context, target, namespace: Type, prefix?: string) => { const data = getData(context, namespace, prefix); if (data) { - context.program.stateMap(XmlStateKeys.nsDeclaration).set(target, data); + if (validateNamespaceIsUri(context, data.namespace)) { + context.program.stateMap(XmlStateKeys.nsDeclaration).set(target, data); + } } }; @@ -80,6 +82,13 @@ function getData( }); return undefined; } + if (prefix !== undefined) { + reportDiagnostic(context.program, { + code: "prefix-not-allowed", + target: context.getArgumentTarget(1)!, + format: { name: namespace.name }, + }); + } if (typeof namespace.value !== "string") { reportDiagnostic(context.program, { code: "invalid-ns-declaration-member", @@ -93,3 +102,17 @@ function getData( return undefined; } } + +function validateNamespaceIsUri(context: DecoratorContext, namespace: string) { + try { + new URL(namespace); + return true; + } catch { + reportDiagnostic(context.program, { + code: "ns-not-uri", + target: context.getArgumentTarget(0)!, + format: { namespace }, + }); + return false; + } +} diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts index cd076fdc97..330a6e752a 100644 --- a/packages/xml/src/lib.ts +++ b/packages/xml/src/lib.ts @@ -26,6 +26,18 @@ export const { default: "When using a string namespace you must provide a prefix as the 2nd argument.", }, }, + "prefix-not-allowed": { + severity: "error", + messages: { + default: "@ns decorator cannot have the prefix parameter set when using an enum member.", + }, + }, + "ns-not-uri": { + severity: "error", + messages: { + default: `Namespace ${"namespace"} is not a valid URI.`, + }, + }, }, state: { attribute: { description: "Mark a model property as to be serialized as xml attribute" }, diff --git a/packages/xml/test/decorators.test.ts b/packages/xml/test/decorators.test.ts index 9c22baaca1..0c91889bbf 100644 --- a/packages/xml/test/decorators.test.ts +++ b/packages/xml/test/decorators.test.ts @@ -152,4 +152,35 @@ describe("@ns", () => { message: "Enum member ns1 must have a value that is the XML namespace url.", }); }); + + it("emit error if providing prefix param with enum member namespace", async () => { + const diagnostics = await runner.diagnose(` + @Xml.nsDeclarations + enum Namespaces { + ns1: "https://example.com/ns1" + } + + model Blob { + @Xml.ns(Namespaces.ns1, "ns2") id : string; + } + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/xml/prefix-not-allowed", + message: "@ns decorator cannot have the prefix parameter set when using an enum member.", + }); + }); + + it("emit error if namespace is not a valid url", async () => { + const diagnostics = await runner.diagnose(` + model Blob { + @Xml.ns("notvalidurl", "ns2") id : string; + } + `); + + expectDiagnostics(diagnostics, { + code: "@typespec/xml/ns-not-uri", + message: "Namespace namespace is not a valid URI.", + }); + }); }); From 147a748dd97e7c910f9fb12aefee1262b8c2b803 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 13:27:17 -0700 Subject: [PATCH 07/35] . --- docs/libraries/xml/reference/decorators.md | 14 +++++++------- packages/xml/README.md | 14 +++++++------- packages/xml/generated-defs/TypeSpec.Xml.ts | 3 +++ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/libraries/xml/reference/decorators.md b/docs/libraries/xml/reference/decorators.md index 1127436ff6..9d9ef334f2 100644 --- a/docs/libraries/xml/reference/decorators.md +++ b/docs/libraries/xml/reference/decorators.md @@ -67,9 +67,9 @@ Provide the name of the XML element or attribute. This is just a syntactic sugar #### Parameters -| Name | Type | Description | -| ---- | ---------------- | ----------- | -| name | `valueof string` | | +| Name | Type | Description | +| ---- | ---------------- | ---------------------------------------- | +| name | `valueof string` | The name of the XML element or attribute | #### Examples @@ -107,10 +107,10 @@ Specify the XML namespace for this element. It can be used in 2 different ways: #### Parameters -| Name | Type | Description | -| ------ | ---------------------- | ----------- | -| ns | `string \| EnumMember` | | -| prefix | `valueof string` | | +| Name | Type | Description | +| ------ | ---------------------- | ---------------------------------------------------------------------------- | +| ns | `string \| EnumMember` | Provide the namespace URI or the enum member where it is defined. | +| prefix | `valueof string` | Provide the name prefix if the namespace parameter was provided as a string. | #### Examples diff --git a/packages/xml/README.md b/packages/xml/README.md index 3119558c0e..36ee17fb51 100644 --- a/packages/xml/README.md +++ b/packages/xml/README.md @@ -77,9 +77,9 @@ Provide the name of the XML element or attribute. This is just a syntactic sugar ##### Parameters -| Name | Type | Description | -| ---- | ---------------- | ----------- | -| name | `valueof string` | | +| Name | Type | Description | +| ---- | ---------------- | ---------------------------------------- | +| name | `valueof string` | The name of the XML element or attribute | ##### Examples @@ -117,10 +117,10 @@ Specify the XML namespace for this element. It can be used in 2 different ways: ##### Parameters -| Name | Type | Description | -| ------ | ---------------------- | ----------- | -| ns | `string \| EnumMember` | | -| prefix | `valueof string` | | +| Name | Type | Description | +| ------ | ---------------------- | ---------------------------------------------------------------------------- | +| ns | `string \| EnumMember` | Provide the namespace URI or the enum member where it is defined. | +| prefix | `valueof string` | Provide the name prefix if the namespace parameter was provided as a string. | ##### Examples diff --git a/packages/xml/generated-defs/TypeSpec.Xml.ts b/packages/xml/generated-defs/TypeSpec.Xml.ts index c84ece94ce..c5e20394c3 100644 --- a/packages/xml/generated-defs/TypeSpec.Xml.ts +++ b/packages/xml/generated-defs/TypeSpec.Xml.ts @@ -3,6 +3,7 @@ import type { DecoratorContext, Enum, ModelProperty, Type } from "@typespec/comp /** * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` * + * @param name The name of the XML element or attribute * @example * ```tsp * @name("XmlBook") @@ -126,6 +127,8 @@ export type UnwrappedDecorator = (context: DecoratorContext, target: ModelProper * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` * + * @param ns Provide the namespace URI or the enum member where it is defined. + * @param prefix Provide the name prefix if the namespace parameter was provided as a string. * @example With strings * * ```tsp From 136bd48b49bc58a3b46954f051cb7d6579e47a0f Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 14:42:16 -0700 Subject: [PATCH 08/35] Fix typo --- packages/xml/README.md | 2 +- packages/xml/generated-defs/TypeSpec.Xml.ts | 2 +- packages/xml/lib/decorators.tsp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/xml/README.md b/packages/xml/README.md index 36ee17fb51..e4ef1d5129 100644 --- a/packages/xml/README.md +++ b/packages/xml/README.md @@ -174,7 +174,7 @@ None #### `@unwrapped` -Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. +Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. It cannot be used with `@attribute`. ```typespec diff --git a/packages/xml/generated-defs/TypeSpec.Xml.ts b/packages/xml/generated-defs/TypeSpec.Xml.ts index c5e20394c3..393db148cb 100644 --- a/packages/xml/generated-defs/TypeSpec.Xml.ts +++ b/packages/xml/generated-defs/TypeSpec.Xml.ts @@ -56,7 +56,7 @@ export type NameDecorator = (context: DecoratorContext, target: Type, name: stri export type AttributeDecorator = (context: DecoratorContext, target: ModelProperty) => void; /** - * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. + * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. * It cannot be used with `@attribute`. * * @example Array property default diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 160038f877..74be882d09 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -63,7 +63,7 @@ extern dec name(target: unknown, name: valueof string); extern dec attribute(target: ModelProperty); /** - * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. + * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. * It cannot be used with `@attribute`. * * @example Array property default From fd7e293e9bc6fec8a8fabcc0512396a310b42c51 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 20 Mar 2024 14:55:50 -0700 Subject: [PATCH 09/35] fix --- docs/libraries/xml/reference/decorators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libraries/xml/reference/decorators.md b/docs/libraries/xml/reference/decorators.md index 9d9ef334f2..a2f38e1bd9 100644 --- a/docs/libraries/xml/reference/decorators.md +++ b/docs/libraries/xml/reference/decorators.md @@ -164,7 +164,7 @@ None ### `@unwrapped` {#@TypeSpec.Xml.unwrapped} -Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be inclued. +Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. It cannot be used with `@attribute`. ```typespec From 6753ff53e67a280b06d03da9055ec46037f43990 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 11:42:13 -0700 Subject: [PATCH 10/35] Missed --- packages/xml/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/xml/package.json b/packages/xml/package.json index 615755ae8f..45329b63de 100644 --- a/packages/xml/package.json +++ b/packages/xml/package.json @@ -51,14 +51,11 @@ "devDependencies": { "@types/node": "~18.11.19", "@typespec/compiler": "workspace:~", - "@typespec/eslint-config-typespec": "workspace:~", - "@typespec/eslint-plugin": "workspace:~", "@typespec/library-linter": "workspace:~", "@typespec/tspd": "workspace:~", "@vitest/coverage-v8": "^1.4.0", "@vitest/ui": "^1.4.0", "c8": "^9.1.0", - "eslint": "^8.57.0", "rimraf": "~5.0.5", "typescript": "~5.4.2", "vitest": "^1.4.0" From 7b04dafcebf45563b3e66dc93742342bca172646 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 11:42:36 -0700 Subject: [PATCH 11/35] Update packages/xml/src/lib.ts Co-authored-by: Mark Cowlishaw --- packages/xml/src/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts index 330a6e752a..ed3efb3c26 100644 --- a/packages/xml/src/lib.ts +++ b/packages/xml/src/lib.ts @@ -45,6 +45,6 @@ export const { description: "Mark a model property as to be serialized without a node wrapping the content.", }, ns: { description: "Namespace data" }, - nsDeclaration: { description: "Mark an enum as declarting Xml Namespaces" }, + nsDeclaration: { description: "Mark an enum that declares Xml Namespaces" }, }, } as const); From 6adc077c3eb64d6ed64b835e678241014f2b446d Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 11:42:42 -0700 Subject: [PATCH 12/35] Update packages/xml/src/lib.ts Co-authored-by: Mark Cowlishaw --- packages/xml/src/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts index ed3efb3c26..4a47bb099e 100644 --- a/packages/xml/src/lib.ts +++ b/packages/xml/src/lib.ts @@ -42,7 +42,7 @@ export const { state: { attribute: { description: "Mark a model property as to be serialized as xml attribute" }, unwrapped: { - description: "Mark a model property as to be serialized without a node wrapping the content.", + description: "Mark a model property to be serialized without a node wrapping the content.", }, ns: { description: "Namespace data" }, nsDeclaration: { description: "Mark an enum that declares Xml Namespaces" }, From 71e751331c2524114990e6f0e60b9d7d1a902874 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 11:42:47 -0700 Subject: [PATCH 13/35] Update packages/xml/src/lib.ts Co-authored-by: Mark Cowlishaw --- packages/xml/src/lib.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/src/lib.ts b/packages/xml/src/lib.ts index 4a47bb099e..ec79f414f0 100644 --- a/packages/xml/src/lib.ts +++ b/packages/xml/src/lib.ts @@ -40,7 +40,7 @@ export const { }, }, state: { - attribute: { description: "Mark a model property as to be serialized as xml attribute" }, + attribute: { description: "Mark a model property to be serialized as xml attribute" }, unwrapped: { description: "Mark a model property to be serialized without a node wrapping the content.", }, From 39581dfcd21b32c83f7db2513969230c1480147b Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 11:47:51 -0700 Subject: [PATCH 14/35] fix --- packages/xml/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/package.json b/packages/xml/package.json index 45329b63de..3f535e6ec1 100644 --- a/packages/xml/package.json +++ b/packages/xml/package.json @@ -57,7 +57,7 @@ "@vitest/ui": "^1.4.0", "c8": "^9.1.0", "rimraf": "~5.0.5", - "typescript": "~5.4.2", + "typescript": "~5.4.3", "vitest": "^1.4.0" } } From 5d13ebf50f32cb2ff6420ecde3d15f49ab095267 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 13:04:55 -0700 Subject: [PATCH 15/35] . --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45006ec6ba..76164877b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1413,7 +1413,7 @@ importers: specifier: ~5.0.5 version: 5.0.5 typescript: - specifier: ~5.4.2 + specifier: ~5.4.3 version: 5.4.3 vitest: specifier: ^1.4.0 From 808d8089de625604e0e6511151bc03681b5c45fd Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 13:38:03 -0700 Subject: [PATCH 16/35] Add tests --- packages/compiler/src/lib/decorators.ts | 26 ++++++++++++--- packages/xml/lib/main.tsp | 1 + packages/xml/lib/types.tsp | 21 ++++++++++++ packages/xml/src/decorators.ts | 14 ++++---- packages/xml/src/encoding.ts | 43 +++++++++++++++++++++++++ packages/xml/src/types.ts | 22 +++++++++++++ packages/xml/test/decorators.test.ts | 4 +-- packages/xml/test/encoding.test.ts | 37 +++++++++++++++++++++ packages/xml/tsconfig.json | 3 +- 9 files changed, 157 insertions(+), 14 deletions(-) create mode 100644 packages/xml/lib/types.tsp create mode 100644 packages/xml/src/encoding.ts create mode 100644 packages/xml/test/encoding.test.ts diff --git a/packages/compiler/src/lib/decorators.ts b/packages/compiler/src/lib/decorators.ts index f7de96b89e..d8b31012b9 100644 --- a/packages/compiler/src/lib/decorators.ts +++ b/packages/compiler/src/lib/decorators.ts @@ -808,17 +808,35 @@ export const $encode: EncodeDecorator = ( ) => { validateDecoratorUniqueOnNode(context, target, $encode); + const encodingStr = computeEncoding(encoding); + if (encodingStr === undefined) { + return; + } const encodeData: EncodeData = { - encoding: - typeof encoding === "string" - ? encoding - : (encoding as any).value?.toString() ?? (encoding as any).name, + encoding: encodingStr, type: encodeAs ?? context.program.checker.getStdType("string"), }; const targetType = getPropertyType(target); validateEncodeData(context, targetType, encodeData); context.program.stateMap(encodeKey).set(target, encodeData); }; +function computeEncoding(encoding: string | Type) { + if (typeof encoding === "string") { + return encoding; + } + switch (encoding.kind) { + case "String": + return encoding.value; + case "EnumMember": + if (encoding.value && typeof encoding.value === "string") { + return encoding.value; + } else { + return getTypeName(encoding); + } + default: + return undefined; + } +} function validateEncodeData(context: DecoratorContext, target: Type, encodeData: EncodeData) { function check(validTargets: StdTypeName[], validEncodeTypes: StdTypeName[]) { diff --git a/packages/xml/lib/main.tsp b/packages/xml/lib/main.tsp index 29ee772dd0..2f34293cb1 100644 --- a/packages/xml/lib/main.tsp +++ b/packages/xml/lib/main.tsp @@ -1 +1,2 @@ +import "./types.tsp"; import "./decorators.tsp"; diff --git a/packages/xml/lib/types.tsp b/packages/xml/lib/types.tsp new file mode 100644 index 0000000000..222d11d398 --- /dev/null +++ b/packages/xml/lib/types.tsp @@ -0,0 +1,21 @@ +namespace TypeSpec.Xml; + +/** + * Known Xml encodings + */ +enum Encoding { + /** Corespond to a field of schema xs:dateTime */ + xmlDateTime, + + /** Corespond to a field of schema xs:date */ + xmlDate, + + /** Corespond to a field of schema xs:time */ + xmlTime, + + /** Corespond to a field of schema xs:duration */ + xmlDuration, + + /** Corespond to a field of schema xs:base64Binary */ + xmlBase64Binary, +} diff --git a/packages/xml/src/decorators.ts b/packages/xml/src/decorators.ts index e93dd2ed4e..bbd37802a1 100644 --- a/packages/xml/src/decorators.ts +++ b/packages/xml/src/decorators.ts @@ -1,12 +1,12 @@ import { $encodedName, - DecoratorContext, - Enum, - ModelProperty, - Program, - Type, + type DecoratorContext, + type Enum, + type ModelProperty, + type Program, + type Type, } from "@typespec/compiler"; -import { +import type { AttributeDecorator, NameDecorator, NsDeclarationsDecorator, @@ -14,7 +14,7 @@ import { UnwrappedDecorator, } from "../generated-defs/TypeSpec.Xml.js"; import { XmlStateKeys, reportDiagnostic } from "./lib.js"; -import { XmlNamespace } from "./types.js"; +import type { XmlNamespace } from "./types.js"; export const namespace = "TypeSpec.Xml"; diff --git a/packages/xml/src/encoding.ts b/packages/xml/src/encoding.ts new file mode 100644 index 0000000000..a53d7cd21d --- /dev/null +++ b/packages/xml/src/encoding.ts @@ -0,0 +1,43 @@ +import { getEncode, type ModelProperty, type Program, type Scalar } from "@typespec/compiler"; +import type { XmlEncodeData, XmlEncoding } from "./types.js"; + +/** + * Resolve how the given type should be encoded in XML. + * This will return the default encoding for each types.(e.g. TypeSpec.Xml.Encoding.xmlDateTime for a utcDatetime) + * @param program + * @param type + * @returns + */ +export function getXmlEncoding( + program: Program, + type: Scalar | ModelProperty +): XmlEncodeData | undefined { + const encodeData = getEncode(program, type); + if (encodeData) { + return encodeData; + } + const def = getDefaultEncoding(type.kind === "Scalar" ? type : (type.type as any)); + if (def === undefined) { + return undefined; + } + + return { encoding: def, type: program.checker.getStdType("string") }; +} + +function getDefaultEncoding(type: Scalar): XmlEncoding | undefined { + switch (type.name) { + case "utcDateTime": + case "offsetDateTime": + return "TypeSpec.Xml.Encoding.xmlDateTime"; + case "plainDate": + return "TypeSpec.Xml.Encoding.xmlDate"; + case "plainTime": + return "TypeSpec.Xml.Encoding.xmlTime"; + case "duration": + return "TypeSpec.Xml.Encoding.xmlDuration"; + case "bytes": + return "TypeSpec.Xml.Encoding.xmlBase64Binary"; + default: + return undefined; + } +} diff --git a/packages/xml/src/types.ts b/packages/xml/src/types.ts index c37d08184e..9fabad38ca 100644 --- a/packages/xml/src/types.ts +++ b/packages/xml/src/types.ts @@ -1,4 +1,26 @@ +import type { EncodeData, Scalar } from "@typespec/compiler"; + export interface XmlNamespace { readonly namespace: string; readonly prefix: string; } + +/** + * Known Xml encodings + */ +export type XmlEncoding = + /** Corespond to a field of schema xs:dateTime */ + | "TypeSpec.Xml.Encoding.xmlDateTime" + /** Corespond to a field of schema xs:date */ + | "TypeSpec.Xml.Encoding.xmlDate" + /** Corespond to a field of schema xs:time */ + | "TypeSpec.Xml.Encoding.xmlTime" + /** Corespond to a field of schema xs:duration */ + | "TypeSpec.Xml.Encoding.xmlDuration" + /** Corespond to a field of schema xs:base64Binary */ + | "TypeSpec.Xml.Encoding.xmlBase64Binary"; + +export interface XmlEncodeData extends EncodeData { + encoding: XmlEncoding | EncodeData["encoding"]; + type: Scalar; +} diff --git a/packages/xml/test/decorators.test.ts b/packages/xml/test/decorators.test.ts index 0c91889bbf..3fe91e83a5 100644 --- a/packages/xml/test/decorators.test.ts +++ b/packages/xml/test/decorators.test.ts @@ -1,5 +1,5 @@ -import { Model, ModelProperty, resolveEncodedName } from "@typespec/compiler"; -import { BasicTestRunner, expectDiagnostics } from "@typespec/compiler/testing"; +import { resolveEncodedName, type Model, type ModelProperty } from "@typespec/compiler"; +import { expectDiagnostics, type BasicTestRunner } from "@typespec/compiler/testing"; import { beforeEach, describe, expect, it } from "vitest"; import { getNs, isAttribute, isUnwrapped } from "../src/decorators.js"; import { createXmlTestRunner } from "./test-host.js"; diff --git a/packages/xml/test/encoding.test.ts b/packages/xml/test/encoding.test.ts new file mode 100644 index 0000000000..3ff3d757ff --- /dev/null +++ b/packages/xml/test/encoding.test.ts @@ -0,0 +1,37 @@ +import type { ModelProperty } from "@typespec/compiler"; +import type { BasicTestRunner } from "@typespec/compiler/testing"; +import { beforeEach, describe, expect, it } from "vitest"; +import { getXmlEncoding } from "../src/encoding.js"; +import { createXmlTestRunner } from "./test-host.js"; + +let runner: BasicTestRunner; + +beforeEach(async () => { + runner = await createXmlTestRunner(); +}); + +describe("default encodings", () => { + it.each([ + ["utcDateTime", "TypeSpec.Xml.Encoding.xmlDateTime"], + ["offsetDateTime", "TypeSpec.Xml.Encoding.xmlDateTime"], + ["duration", "TypeSpec.Xml.Encoding.xmlDuration"], + ["plainDate", "TypeSpec.Xml.Encoding.xmlDate"], + ["plainTime", "TypeSpec.Xml.Encoding.xmlTime"], + ["bytes", "TypeSpec.Xml.Encoding.xmlBase64Binary"], + ])("%s", async (type, expectedEncoding) => { + const { prop } = (await runner.compile(`model Foo { + @test prop: ${type} + }`)) as { prop: ModelProperty }; + const encoding = getXmlEncoding(runner.program, prop); + expect(encoding?.encoding).toEqual(expectedEncoding); + }); +}); + +it("override encoding", async () => { + const { prop } = (await runner.compile(`model Foo { + @encode("rfc3339") + @test prop: utcDateTime; + }`)) as { prop: ModelProperty }; + const encoding = getXmlEncoding(runner.program, prop); + expect(encoding?.encoding).toEqual("rfc3339"); +}); diff --git a/packages/xml/tsconfig.json b/packages/xml/tsconfig.json index b73ccb236b..a805ea7ada 100644 --- a/packages/xml/tsconfig.json +++ b/packages/xml/tsconfig.json @@ -5,7 +5,8 @@ "outDir": "dist", "rootDir": ".", "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", - "lib": ["DOM", "ESNext"] + "lib": ["DOM", "ESNext"], + "verbatimModuleSyntax": true }, "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] } From 356869efc5a2371df67404fd9c4edda65af277a6 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 13:41:59 -0700 Subject: [PATCH 17/35] Create feature-xml-2024-3-8-20-40-16.md --- .chronus/changes/feature-xml-2024-3-8-20-40-16.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .chronus/changes/feature-xml-2024-3-8-20-40-16.md diff --git a/.chronus/changes/feature-xml-2024-3-8-20-40-16.md b/.chronus/changes/feature-xml-2024-3-8-20-40-16.md new file mode 100644 index 0000000000..5cfb83e8b6 --- /dev/null +++ b/.chronus/changes/feature-xml-2024-3-8-20-40-16.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: feature +packages: + - "@typespec/compiler" +--- + +`getEncode` returns the fully equalied enum member name if using a custom enum. From fdc1edf470088f6d4467d07917f2ef7c353933bd Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 13:43:55 -0700 Subject: [PATCH 18/35] add doc --- packages/xml/src/decorators.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/xml/src/decorators.ts b/packages/xml/src/decorators.ts index bbd37802a1..65b3d0e0de 100644 --- a/packages/xml/src/decorators.ts +++ b/packages/xml/src/decorators.ts @@ -26,6 +26,9 @@ export const $attribute: AttributeDecorator = (context, target) => { context.program.stateSet(XmlStateKeys.attribute).add(target); }; +/** + * Check if the given property should be serialized as an attribute instead of a node. + */ export function isAttribute(program: Program, target: ModelProperty): boolean { return program.stateSet(XmlStateKeys.attribute).has(target); } @@ -34,6 +37,9 @@ export const $unwrapped: UnwrappedDecorator = (context, target) => { context.program.stateSet(XmlStateKeys.unwrapped).add(target); }; +/** + * Check if the given property should be unwrapped in the XML containing node. + */ export function isUnwrapped(program: Program, target: ModelProperty): boolean { return program.stateSet(XmlStateKeys.unwrapped).has(target); } @@ -55,6 +61,9 @@ export const $ns: NsDecorator = (context, target, namespace: Type, prefix?: stri } }; +/** + * Get the namespace and prefix for the given type. + */ export function getNs(program: Program, target: Type): XmlNamespace | undefined { return program.stateMap(XmlStateKeys.nsDeclaration).get(target); } From 66956b778c8fd5e04611a57a308a99fe77c1cc4a Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 13:46:19 -0700 Subject: [PATCH 19/35] Add default encoding docs --- docs/libraries/xml/guide.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md index f318fa19fa..e09cfb33ec 100644 --- a/docs/libraries/xml/guide.md +++ b/docs/libraries/xml/guide.md @@ -4,6 +4,19 @@ title: Guide # Xml Library +## Default encoding of scalars + +As in Json we need to have some [default handling](https://typespec.io/docs/libraries/http/encoding#bytes) of the common scalars like `utcDateTime` + +| Scalar Type | Default Encoding | Encoding name | +| ---------------- | ----------------- | --------------------------------------- | +| `utcDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | +| `offsetDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | +| `plainDate` | `xs:date` | `TypeSpec.Xml.Encoding.xmlDate` | +| `plainTime` | `xs:time` | `TypeSpec.Xml.Encoding.xmlTim` | +| `duration` | `xs:duration` | `TypeSpec.Xml.Encoding.xmlDuration` | +| `bytes` | `xs:base64Binary` | `TypeSpec.Xml.Encoding.xmlBase64Binary` | + ## Examples ### 1. Array of primitive types From c360126f17487a15c2eaac14b1a80d20645a228a Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Mon, 8 Apr 2024 16:57:50 -0700 Subject: [PATCH 20/35] fix --- packages/xml/tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/xml/tsconfig.json b/packages/xml/tsconfig.json index a805ea7ada..b73ccb236b 100644 --- a/packages/xml/tsconfig.json +++ b/packages/xml/tsconfig.json @@ -5,8 +5,7 @@ "outDir": "dist", "rootDir": ".", "tsBuildInfoFile": "temp/tsconfig.tsbuildinfo", - "lib": ["DOM", "ESNext"], - "verbatimModuleSyntax": true + "lib": ["DOM", "ESNext"] }, "include": ["src/**/*.ts", "generated-defs/**/*.ts", "test/**/*.ts"] } From 2631062aa30f31258f830f89a42e446df8bb1e32 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:09:30 -0700 Subject: [PATCH 21/35] Update docs/libraries/xml/guide.md Co-authored-by: Brian Terlson --- docs/libraries/xml/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md index e09cfb33ec..e9cf1320c5 100644 --- a/docs/libraries/xml/guide.md +++ b/docs/libraries/xml/guide.md @@ -6,7 +6,7 @@ title: Guide ## Default encoding of scalars -As in Json we need to have some [default handling](https://typespec.io/docs/libraries/http/encoding#bytes) of the common scalars like `utcDateTime` +As in Json we have some [default handling](https://typespec.io/docs/libraries/http/encoding#bytes) of the common scalars like `utcDateTime` | Scalar Type | Default Encoding | Encoding name | | ---------------- | ----------------- | --------------------------------------- | From 7ba585cf5272e54aed3f43cbcff603208150c36b Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:09:40 -0700 Subject: [PATCH 22/35] Update docs/libraries/xml/guide.md Co-authored-by: Brian Terlson --- docs/libraries/xml/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md index e9cf1320c5..9dec443a60 100644 --- a/docs/libraries/xml/guide.md +++ b/docs/libraries/xml/guide.md @@ -13,7 +13,7 @@ As in Json we have some [default handling](https://typespec.io/docs/libraries/ht | `utcDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | | `offsetDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | | `plainDate` | `xs:date` | `TypeSpec.Xml.Encoding.xmlDate` | -| `plainTime` | `xs:time` | `TypeSpec.Xml.Encoding.xmlTim` | +| `plainTime` | `xs:time` | `TypeSpec.Xml.Encoding.xmlTime` | | `duration` | `xs:duration` | `TypeSpec.Xml.Encoding.xmlDuration` | | `bytes` | `xs:base64Binary` | `TypeSpec.Xml.Encoding.xmlBase64Binary` | From f6d4f1f20abbe222886f6ac519c678680a959e82 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:10:05 -0700 Subject: [PATCH 23/35] Update docs/libraries/xml/reference/index.mdx Co-authored-by: Brian Terlson --- docs/libraries/xml/reference/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libraries/xml/reference/index.mdx b/docs/libraries/xml/reference/index.mdx index 6b1f7600a9..963de05a6b 100644 --- a/docs/libraries/xml/reference/index.mdx +++ b/docs/libraries/xml/reference/index.mdx @@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem'; # Overview -TypeSpec library providing xml bindings +TypeSpec library providing xml bindings. ## Install From 0fea426bb5fffcb7b0738f0ff841bfd4cca99f81 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:10:09 -0700 Subject: [PATCH 24/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 74be882d09..7787ba608d 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -5,7 +5,8 @@ using TypeSpec.Reflection; namespace TypeSpec.Xml; /** - * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + * Provide the name of the XML element or attribute. This means the same thing as + `@encodedName("application/xml", value)` * * @param name The name of the XML element or attribute * From d1629f05b08bc234fce890eed3e854ea046a4f31 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:10:16 -0700 Subject: [PATCH 25/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 7787ba608d..4f6a67da9c 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -135,7 +135,7 @@ extern dec unwrapped(target: ModelProperty); /** * Specify the XML namespace for this element. It can be used in 2 different ways: - * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element + * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` * * @param ns Provide the namespace URI or the enum member where it is defined. From 636666c2d907b48e0282bf8927266a21ede8e610 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:10:27 -0700 Subject: [PATCH 26/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 4f6a67da9c..4cca56d67f 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -136,7 +136,7 @@ extern dec unwrapped(target: ModelProperty); /** * Specify the XML namespace for this element. It can be used in 2 different ways: * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix - * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + * 2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` * * @param ns Provide the namespace URI or the enum member where it is defined. * @param prefix Provide the name prefix if the namespace parameter was provided as a string. From 1500ea23b4832905be46eeed4eae0a43e82afaa4 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:10:32 -0700 Subject: [PATCH 27/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 4cca56d67f..e5cb9cf6fe 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -138,7 +138,7 @@ extern dec unwrapped(target: ModelProperty); * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix * 2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` * - * @param ns Provide the namespace URI or the enum member where it is defined. + * @param ns The namespace URI or a member of an enum decorated with `@nsDeclaration`. * @param prefix Provide the name prefix if the namespace parameter was provided as a string. * * @example With strings From b3034ebd6d7f97e1785e42e82b1e51703aa5e064 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:12:59 -0700 Subject: [PATCH 28/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index e5cb9cf6fe..23cdf44eb3 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -139,7 +139,7 @@ extern dec unwrapped(target: ModelProperty); * 2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` * * @param ns The namespace URI or a member of an enum decorated with `@nsDeclaration`. - * @param prefix Provide the name prefix if the namespace parameter was provided as a string. + * @param prefix The namespace prefix. Required if the namespace parameter was passed as a string. * * @example With strings * From 80f22270c9f26d6abbe7f311fe3c6deed4f0fc3d Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:13:05 -0700 Subject: [PATCH 29/35] Update packages/xml/lib/types.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/types.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/types.tsp b/packages/xml/lib/types.tsp index 222d11d398..5234c78224 100644 --- a/packages/xml/lib/types.tsp +++ b/packages/xml/lib/types.tsp @@ -4,7 +4,7 @@ namespace TypeSpec.Xml; * Known Xml encodings */ enum Encoding { - /** Corespond to a field of schema xs:dateTime */ + /** Corresponds to a field of schema xs:dateTime */ xmlDateTime, /** Corespond to a field of schema xs:date */ From a6d348357216e177b9215b7b027099ea45c33659 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:13:11 -0700 Subject: [PATCH 30/35] Update packages/xml/lib/decorators.tsp Co-authored-by: Brian Terlson --- packages/xml/lib/decorators.tsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/xml/lib/decorators.tsp b/packages/xml/lib/decorators.tsp index 23cdf44eb3..82267290a0 100644 --- a/packages/xml/lib/decorators.tsp +++ b/packages/xml/lib/decorators.tsp @@ -64,7 +64,7 @@ extern dec name(target: unknown, name: valueof string); extern dec attribute(target: ModelProperty); /** - * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. + * Specify that the target property shouldn't create a wrapper node. This can be used to flatten list nodes into the model node or to include raw text in the model node. * It cannot be used with `@attribute`. * * @example Array property default From 3cd20482ba43d36d572a0bce8b8661957d0b9ce3 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:17:00 -0700 Subject: [PATCH 31/35] remove column --- docs/libraries/xml/guide.md | 139 ++---------------------------------- 1 file changed, 5 insertions(+), 134 deletions(-) diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md index 9dec443a60..e5076feb84 100644 --- a/docs/libraries/xml/guide.md +++ b/docs/libraries/xml/guide.md @@ -23,7 +23,6 @@ As in Json we have some [default handling](https://typespec.io/docs/libraries/ht - @@ -32,14 +31,6 @@ As in Json we have some [default handling](https://typespec.io/docs/libraries/ht - - - -
Scenario TypeSpec Xml OpenAPI3
-**Scenario 1.1:** - -- ❌ ItemsName -- ❌ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -80,14 +71,6 @@ Pet:
-**Scenario 1.2:** - -- ❌ ItemsName -- ✅ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -133,14 +116,6 @@ Pet:
-**Scenario 1.3:** - -- ✅ ItemsName -- ❌ Wrapped - - - ```tsp @encodedName("application/xml", "ItemsName") scalar tag extends string; @@ -188,14 +163,6 @@ Pet:
-**Scenario 1.4:** - -- ✅ ItemsName -- ✅ Wrapped - - - ```tsp @encodedName("application/xml", "ItemsName") scalar tag extends string; @@ -249,7 +216,6 @@ Pet: - @@ -258,14 +224,6 @@ Pet: - - - -
Scenario TypeSpec Xml OpenAPI3
-**Scenario 2.1:** - -- ❌ ItemsName -- ❌ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -319,14 +277,6 @@ Pet:
-**Scenario 2.2:** - -- ❌ ItemsName -- ✅ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -384,14 +334,6 @@ Pet:
-**Scenario 2.3:** - -- ✅ ItemsName -- ❌ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -450,14 +392,6 @@ Tag:
-**Scenario 2.4:** - -- ✅ ItemsName -- ✅ Wrapped - - - ```tsp @encodedName("application/xml", "XmlPet") model Pet { @@ -517,7 +451,7 @@ Pet: - + @@ -526,13 +460,6 @@ Pet: - - -
ScenarioTypeSpec Xml OpenAPI3
-**Scenario 3.1:** - -No annotations - - - ```tsp model Book { author: Author; @@ -577,15 +504,6 @@ Author:
-**Scenario 3.2:** - -Nested model has xml encoded name. - -_⚠️ no op in serialization of Book_ - - - ```tsp model Book { author: Author; @@ -636,13 +554,6 @@ Author:
-**Scenario 3.2:** - -Property has encoded name - - - ```tsp model Book { @encodedName("application/xml", "xml-author") @@ -695,7 +606,7 @@ Author: - + @@ -704,13 +615,6 @@ Author: -
ScenarioTypeSpec Xml OpenAPI3
-**Scenario 4.1:** - -Convert a property to an attribute - - - ```tsp model Book { @Xml.attribute @@ -759,7 +663,7 @@ Book: - + @@ -768,13 +672,6 @@ Book: - -
ScenarioTypeSpec Xml OpenAPI3
-**Scenario 5.1:** - -On model - - - ```tsp @Xml.ns("smp", "http://example.com/schema") model Book { @@ -820,13 +717,6 @@ Book:
-**Scenario 5.2:** - -On model and properties - - - ```tsp @Xml.ns("smp", "http://example.com/schema") model Book { @@ -886,7 +776,7 @@ Book: - + @@ -895,13 +785,6 @@ Book: - -
ScenarioTypeSpec Xml OpenAPI3
-**Scenario 6.1:** - -On model - - - ```tsp @Xml.nsDeclarations enum Namespaces { @@ -952,13 +835,6 @@ Book:
-**Scenario 6.2:** - -On model and properties - - - ```tsp @Xml.nsDeclarations enum Namespaces { @@ -1024,7 +900,7 @@ Book: - + @@ -1033,11 +909,6 @@ Book: -
ScenarioTypeSpec Xml OpenAPI3
-**Scenario 6.1:** - - - ```tsp model BlobName { @Xml.attribute language: string; From b475fe35ac5879ea4e51a72f9933fb650474a3bc Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:17:42 -0700 Subject: [PATCH 32/35] format --- docs/libraries/xml/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/libraries/xml/guide.md b/docs/libraries/xml/guide.md index e5076feb84..f7860abe97 100644 --- a/docs/libraries/xml/guide.md +++ b/docs/libraries/xml/guide.md @@ -13,7 +13,7 @@ As in Json we have some [default handling](https://typespec.io/docs/libraries/ht | `utcDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | | `offsetDateTime` | `xs:dateTime` | `TypeSpec.Xml.Encoding.xmlDateTime` | | `plainDate` | `xs:date` | `TypeSpec.Xml.Encoding.xmlDate` | -| `plainTime` | `xs:time` | `TypeSpec.Xml.Encoding.xmlTime` | +| `plainTime` | `xs:time` | `TypeSpec.Xml.Encoding.xmlTime` | | `duration` | `xs:duration` | `TypeSpec.Xml.Encoding.xmlDuration` | | `bytes` | `xs:base64Binary` | `TypeSpec.Xml.Encoding.xmlBase64Binary` | From b4587f9507d26a7459524ab1817b05062c3aa0c7 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:18:51 -0700 Subject: [PATCH 33/35] . --- packages/xml/generated-defs/TypeSpec.Xml.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/xml/generated-defs/TypeSpec.Xml.ts b/packages/xml/generated-defs/TypeSpec.Xml.ts index 393db148cb..053f99a305 100644 --- a/packages/xml/generated-defs/TypeSpec.Xml.ts +++ b/packages/xml/generated-defs/TypeSpec.Xml.ts @@ -1,7 +1,8 @@ import type { DecoratorContext, Enum, ModelProperty, Type } from "@typespec/compiler"; /** - * Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` + * Provide the name of the XML element or attribute. This means the same thing as + * `@encodedName("application/xml", value)` * * @param name The name of the XML element or attribute * @example @@ -56,7 +57,7 @@ export type NameDecorator = (context: DecoratorContext, target: Type, name: stri export type AttributeDecorator = (context: DecoratorContext, target: ModelProperty) => void; /** - * Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. + * Specify that the target property shouldn't create a wrapper node. This can be used to flatten list nodes into the model node or to include raw text in the model node. * It cannot be used with `@attribute`. * * @example Array property default @@ -124,11 +125,11 @@ export type UnwrappedDecorator = (context: DecoratorContext, target: ModelProper /** * Specify the XML namespace for this element. It can be used in 2 different ways: - * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element - * 2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` + * 1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix + * 2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` * - * @param ns Provide the namespace URI or the enum member where it is defined. - * @param prefix Provide the name prefix if the namespace parameter was provided as a string. + * @param ns The namespace URI or a member of an enum decorated with `@nsDeclaration`. + * @param prefix The namespace prefix. Required if the namespace parameter was passed as a string. * @example With strings * * ```tsp From 0b024aebbdbad712cd32dbae1a6d4bc37c67a41e Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 10:42:57 -0700 Subject: [PATCH 34/35] regen docs --- docs/libraries/xml/reference/decorators.md | 17 +++++++++-------- docs/libraries/xml/reference/index.mdx | 2 +- packages/xml/README.md | 17 +++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/libraries/xml/reference/decorators.md b/docs/libraries/xml/reference/decorators.md index a2f38e1bd9..0f384c07cb 100644 --- a/docs/libraries/xml/reference/decorators.md +++ b/docs/libraries/xml/reference/decorators.md @@ -55,7 +55,8 @@ model Blob { ### `@name` {#@TypeSpec.Xml.name} -Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` +Provide the name of the XML element or attribute. This means the same thing as +`@encodedName("application/xml", value)` ```typespec @TypeSpec.Xml.name(name: valueof string) @@ -94,8 +95,8 @@ model Book { Specify the XML namespace for this element. It can be used in 2 different ways: -1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element -2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` +1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix +2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` ```typespec @TypeSpec.Xml.ns(ns: string | EnumMember, prefix?: valueof string) @@ -107,10 +108,10 @@ Specify the XML namespace for this element. It can be used in 2 different ways: #### Parameters -| Name | Type | Description | -| ------ | ---------------------- | ---------------------------------------------------------------------------- | -| ns | `string \| EnumMember` | Provide the namespace URI or the enum member where it is defined. | -| prefix | `valueof string` | Provide the name prefix if the namespace parameter was provided as a string. | +| Name | Type | Description | +| ------ | ---------------------- | --------------------------------------------------------------------------------- | +| ns | `string \| EnumMember` | The namespace URI or a member of an enum decorated with `@nsDeclaration`. | +| prefix | `valueof string` | The namespace prefix. Required if the namespace parameter was passed as a string. | #### Examples @@ -164,7 +165,7 @@ None ### `@unwrapped` {#@TypeSpec.Xml.unwrapped} -Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. +Specify that the target property shouldn't create a wrapper node. This can be used to flatten list nodes into the model node or to include raw text in the model node. It cannot be used with `@attribute`. ```typespec diff --git a/docs/libraries/xml/reference/index.mdx b/docs/libraries/xml/reference/index.mdx index 963de05a6b..6b1f7600a9 100644 --- a/docs/libraries/xml/reference/index.mdx +++ b/docs/libraries/xml/reference/index.mdx @@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem'; # Overview -TypeSpec library providing xml bindings. +TypeSpec library providing xml bindings ## Install diff --git a/packages/xml/README.md b/packages/xml/README.md index e4ef1d5129..ccc52c5a9a 100644 --- a/packages/xml/README.md +++ b/packages/xml/README.md @@ -65,7 +65,8 @@ model Blob { #### `@name` -Provide the name of the XML element or attribute. This is just a syntactic sugar for `@encodedName("application/xml", value)` +Provide the name of the XML element or attribute. This means the same thing as +`@encodedName("application/xml", value)` ```typespec @TypeSpec.Xml.name(name: valueof string) @@ -104,8 +105,8 @@ model Book { Specify the XML namespace for this element. It can be used in 2 different ways: -1. `@ns("http://www.example.com/namespace", "ns1")` - specify the default namespace for the element -2. `@Xml.ns(Namespaces.ns1)` - Using an enum marked with `@nsDeclaration` +1. `@ns("http://www.example.com/namespace", "ns1")` - specify both namespace and prefix +2. `@Xml.ns(Namespaces.ns1)` - pass a member of an enum decorated with `@nsDeclaration` ```typespec @TypeSpec.Xml.ns(ns: string | EnumMember, prefix?: valueof string) @@ -117,10 +118,10 @@ Specify the XML namespace for this element. It can be used in 2 different ways: ##### Parameters -| Name | Type | Description | -| ------ | ---------------------- | ---------------------------------------------------------------------------- | -| ns | `string \| EnumMember` | Provide the namespace URI or the enum member where it is defined. | -| prefix | `valueof string` | Provide the name prefix if the namespace parameter was provided as a string. | +| Name | Type | Description | +| ------ | ---------------------- | --------------------------------------------------------------------------------- | +| ns | `string \| EnumMember` | The namespace URI or a member of an enum decorated with `@nsDeclaration`. | +| prefix | `valueof string` | The namespace prefix. Required if the namespace parameter was passed as a string. | ##### Examples @@ -174,7 +175,7 @@ None #### `@unwrapped` -Specify that the target property shouldn't create a wrapper node. This allow array properties to be flattened inside the model node or raw text to be included. +Specify that the target property shouldn't create a wrapper node. This can be used to flatten list nodes into the model node or to include raw text in the model node. It cannot be used with `@attribute`. ```typespec From bdb2e1149177e1f98e8c6fe78552854287bee3ca Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 9 Apr 2024 15:19:58 -0700 Subject: [PATCH 35/35] missing exports --- packages/xml/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/xml/src/index.ts b/packages/xml/src/index.ts index 48287a408a..1bd5b77882 100644 --- a/packages/xml/src/index.ts +++ b/packages/xml/src/index.ts @@ -8,4 +8,5 @@ export { isAttribute, isUnwrapped, } from "./decorators.js"; -export type { XmlNamespace } from "./types.js"; +export { getXmlEncoding } from "./encoding.js"; +export type { XmlEncodeData, XmlEncoding, XmlNamespace } from "./types.js";