diff --git a/packages/samples/specs/data-plane/azure-core-scalars/main.tsp b/packages/samples/specs/data-plane/azure-core-scalars/main.tsp index 6632408b2d..083b998299 100644 --- a/packages/samples/specs/data-plane/azure-core-scalars/main.tsp +++ b/packages/samples/specs/data-plane/azure-core-scalars/main.tsp @@ -9,7 +9,7 @@ using Versioning; using Azure.Core; using Azure.Core.Traits; -@service +@service(#{ title: "Azure Core Scalars" }) @versioned(Contoso.WidgetManager.Versions) @useAuth(ApiKeyAuth) namespace Contoso.WidgetManager; diff --git a/packages/samples/specs/data-plane/widget-manager/sample-config.yaml b/packages/samples/specs/data-plane/widget-manager/sample-config.yaml index bb370374e2..c1331f2a49 100644 --- a/packages/samples/specs/data-plane/widget-manager/sample-config.yaml +++ b/packages/samples/specs/data-plane/widget-manager/sample-config.yaml @@ -2,3 +2,4 @@ title: Widget Manager description: Sample configuration for widget-manager in data-plane. llmstxt: true +order: 1 diff --git a/packages/samples/specs/resource-manager/legacy/sample-config.yaml b/packages/samples/specs/resource-manager/legacy/sample-config.yaml index 0b28ce07ea..ba935cbfb7 100644 --- a/packages/samples/specs/resource-manager/legacy/sample-config.yaml +++ b/packages/samples/specs/resource-manager/legacy/sample-config.yaml @@ -1,3 +1,4 @@ directory: true danger: These samples are for grandfathered specs only and should not be used for new specs. order: 1000 +playground: false diff --git a/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@azure-tools/typespec-autorest/2022-08-31/openapi.json b/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@azure-tools/typespec-autorest/2022-08-31/openapi.json index adb44e9a07..94345f2095 100644 --- a/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@azure-tools/typespec-autorest/2022-08-31/openapi.json +++ b/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@azure-tools/typespec-autorest/2022-08-31/openapi.json @@ -1,7 +1,7 @@ { "swagger": "2.0", "info": { - "title": "(title)", + "title": "Azure Core Scalars", "version": "2022-08-31", "x-typespec-generated": [ { diff --git a/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@typespec/openapi3/openapi.2022-08-31.yaml b/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@typespec/openapi3/openapi.2022-08-31.yaml index 52234108dd..d88417f898 100644 --- a/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@typespec/openapi3/openapi.2022-08-31.yaml +++ b/packages/samples/test/output/azure/core/data-plane/azure-core-scalars/@typespec/openapi3/openapi.2022-08-31.yaml @@ -1,6 +1,6 @@ openapi: 3.0.0 info: - title: (title) + title: Azure Core Scalars version: '2022-08-31' tags: [] paths: diff --git a/packages/typespec-azure-playground-website/e2e/smoke.e2e.ts b/packages/typespec-azure-playground-website/e2e/smoke.e2e.ts index bb29dab71d..5c7941782f 100644 --- a/packages/typespec-azure-playground-website/e2e/smoke.e2e.ts +++ b/packages/typespec-azure-playground-website/e2e/smoke.e2e.ts @@ -9,7 +9,8 @@ test.describe("typespec-azure-playground-website UI tests", () => { await page.goto(host); const samplesButton = page.locator('button[aria-label="Browse samples"]'); await samplesButton.click(); - await page.locator("text=Azure Resource Manager framework").first().click(); - await expect(page.getByText(`"title": "ContosoProviderHubClient"`)).toBeVisible(); + await page.locator("text=Azure Core Scalars").first().click(); + // Check the version is there + await expect(page.getByText(`"title": "Azure Core Scalars"`)).toBeVisible(); }); }); diff --git a/packages/typespec-azure-playground-website/index.html b/packages/typespec-azure-playground-website/index.html index 5629aa8d60..a313517e13 100644 --- a/packages/typespec-azure-playground-website/index.html +++ b/packages/typespec-azure-playground-website/index.html @@ -2,7 +2,6 @@ - TypeSpec Azure Playground diff --git a/packages/typespec-azure-playground-website/package.json b/packages/typespec-azure-playground-website/package.json index c1faeee107..51d4423a5c 100644 --- a/packages/typespec-azure-playground-website/package.json +++ b/packages/typespec-azure-playground-website/package.json @@ -33,8 +33,9 @@ }, "scripts": { "clean": "rimraf ./dist ./dist-dev ./temp ./samples/dist", - "build-samples": "node ./samples/build.js", + "build-samples": "tsx ./samples/build.ts", "build": "npm run build-samples && tsc -p tsconfig.build.json && vite build 2>&1", + "preview": "pnpm build && vite preview", "start": "npm run -s watch", "test": "vitest run", "test:ci": "vitest run", @@ -74,7 +75,8 @@ "es-module-shims": "catalog:", "react": "catalog:", "react-dom": "catalog:", - "vite": "catalog:" + "vite": "catalog:", + "yaml": "catalog:" }, "devDependencies": { "@playwright/test": "catalog:", @@ -86,6 +88,7 @@ "@vitest/coverage-v8": "catalog:", "@vitest/ui": "catalog:", "cross-env": "catalog:", + "pathe": "catalog:", "rimraf": "catalog:", "typescript": "catalog:", "vitest": "catalog:" diff --git a/packages/typespec-azure-playground-website/samples/arm.tsp b/packages/typespec-azure-playground-website/samples/arm.tsp deleted file mode 100644 index 7ee9f885e5..0000000000 --- a/packages/typespec-azure-playground-website/samples/arm.tsp +++ /dev/null @@ -1,129 +0,0 @@ -import "@typespec/http"; -import "@typespec/rest"; -import "@typespec/versioning"; -import "@azure-tools/typespec-azure-core"; -import "@azure-tools/typespec-azure-resource-manager"; - -using Http; -using Rest; -using Versioning; -using Azure.Core; -using Azure.ResourceManager; - -/** Contoso Resource Provider management API. */ -@armProviderNamespace -@service(#{ title: "ContosoProviderHubClient" }) -@versioned(Versions) -namespace Microsoft.ContosoProviderHub; - -/** Contoso API versions */ -enum Versions { - /** 2021-10-01-preview version */ - @armCommonTypesVersion(Azure.ResourceManager.CommonTypes.Versions.v5) - @previewVersion - `2021-10-01-preview`, -} - -/** A ContosoProviderHub resource */ -model Employee is TrackedResource { - ...ResourceNameParameter; -} - -/** Employee properties */ -model EmployeeProperties { - /** Age of employee */ - age?: int32; - - /** City of employee */ - city?: string; - - /** Profile of employee */ - @encode("base64url") - profile?: bytes; - - /** The status of the last operation. */ - @visibility(Lifecycle.Read) - provisioningState?: ProvisioningState; -} - -/** The provisioning state of a resource. */ -@lroStatus -union ProvisioningState { - string, - - /** The resource create request has been accepted */ - Accepted: "Accepted", - - /** The resource is being provisioned */ - Provisioning: "Provisioning", - - /** The resource is updating */ - Updating: "Updating", - - /** Resource has been created. */ - Succeeded: "Succeeded", - - /** Resource creation failed. */ - Failed: "Failed", - - /** Resource creation was canceled. */ - Canceled: "Canceled", - - /** The resource is being deleted */ - Deleting: "Deleting", -} - -/** Employee update request body */ -model EmployeeUpdate { - /** Resource tags. */ - ...Azure.ResourceManager.Foundations.ArmTagsProperty; - - /** The resource-specific properties for this resource. */ - properties?: EmployeeUpdateProperties; -} - -/** Employee update properties */ -model EmployeeUpdateProperties { - /** Age of employee */ - age?: int32; - - /** City of employee */ - city?: string; - - /** Profile of employee */ - @encode("base64url") - profile?: bytes; -} - -/** Employee move request */ -model MoveRequest { - /** The moving from location */ - from: string; - - /** The moving to location */ - to: string; -} - -/** Employee move response */ -model MoveResponse { - /** The status of the move */ - movingStatus: string; -} - -interface Operations extends Azure.ResourceManager.Operations {} - -@armResourceOperations -interface Employees { - get is ArmResourceRead; - createOrUpdate is ArmResourceCreateOrReplaceAsync; - update is ArmCustomPatchSync; - delete is ArmResourceDeleteWithoutOkAsync; - listByResourceGroup is ArmResourceListByParent; - listBySubscription is ArmListBySubscription; - - /** A sample resource action that move employee to different location */ - move is ArmResourceActionSync; - - /** A sample HEAD operation to check resource existence */ - checkExistence is ArmResourceCheckExistence; -} diff --git a/packages/typespec-azure-playground-website/samples/azure-core.tsp b/packages/typespec-azure-playground-website/samples/azure-core.tsp deleted file mode 100644 index 713e46fa36..0000000000 --- a/packages/typespec-azure-playground-website/samples/azure-core.tsp +++ /dev/null @@ -1,295 +0,0 @@ -import "@typespec/http"; -import "@typespec/rest"; -import "@typespec/versioning"; -import "@azure-tools/typespec-azure-core"; - -using Http; -using Rest; -using Versioning; -using Azure.Core; -using Azure.Core.Traits; - -@useAuth( - - | ApiKeyAuth - | OAuth2Auth<[ - { - type: OAuth2FlowType.implicit, - authorizationUrl: "https://login.contoso.com/common/oauth2/v2.0/authorize", - scopes: ["https://widget.contoso.com/.default"], - } - ]> -) -@service(#{ title: "Contoso Widget Manager" }) -@server( - "{endpoint}/widget", - "Contoso Widget APIs", - { - /** -Supported Widget Services endpoints (protocol and hostname, for example: -https://westus.api.widget.contoso.com). - */ - endpoint: url, - } -) -@versioned(Contoso.WidgetManager.Versions) -namespace Contoso.WidgetManager; - -/** The Contoso Widget Manager service version. */ -enum Versions { - /** Version 2022-08-31 */ - `2022-08-30`, -} - -// Models //////////////////// - -/** The color of a widget. */ -union WidgetColor { - string, - - /** Black Widget Color */ - Black: "Black", - - /** White Widget Color */ - White: "White", - - /** Red Widget Color */ - Red: "Red", - - /** Green Widget Color */ - Green: "Green", - - /** Blue Widget Color */ - Blue: "Blue", -} - -/** A widget. */ -@resource("widgets") -model Widget { - /** The widget name. */ - @key("widgetName") - @visibility(Lifecycle.Read) - name: string; - - /** The widget color. */ - color: WidgetColor; - - /** The ID of the widget's manufacturer. */ - manufacturerId: string; - - ...EtagProperty; -} - -/** The repair state of a widget. */ -@lroStatus -union WidgetRepairState { - string, - - /** Widget repairs succeeded. */ - Succeeded: "Succeeded", - - /** Widget repairs failed. */ - Failed: "Failed", - - /** Widget repairs were canceled. */ - Canceled: "Canceled", - - /** Widget was sent to the manufacturer. */ - SentToManufacturer: "SentToManufacturer", -} - -/** A submitted repair request for a widget. */ -model WidgetRepairRequest { - /** The state of the widget repair request. */ - requestState: WidgetRepairState; - - /** The date and time when the repair is scheduled to occur. */ - scheduledDateTime: utcDateTime; - - /** The date and time when the request was created. */ - createdDateTime: utcDateTime; - - /** The date and time when the request was updated. */ - updatedDateTime: utcDateTime; - - /** The date and time when the request was completed. */ - completedDateTime: utcDateTime; -} - -/** The parameters for a widget status request */ -model WidgetRepairStatusParams { - /** The ID of the widget being repaired. */ - @path - widgetId: string; -} - -/** A widget's part. */ -@resource("parts") -@parentResource(Widget) -model WidgetPart { - /** The name of the part. */ - @key("widgetPartName") - @visibility(Lifecycle.Read) - name: string; - - /** The ID to use for reordering the part. */ - partId: string; - - /** The ID of the part's manufacturer. */ - manufacturerId: string; - - ...EtagProperty; -} - -/** The details of a reorder request for a WidgetPart. */ -model WidgetPartReorderRequest { - /** Identifies who signed off the reorder request. */ - signedOffBy: string; -} - -// An example of a singleton resource -/** Provides analytics about the use and maintenance of a Widget. */ -@resource("analytics") -@parentResource(Widget) -model WidgetAnalytics { - /** The identifier for the analytics object. There is only one named 'current'. */ - @key("analyticsId") - @visibility(Lifecycle.Read) - id: "current"; - - /** The number of uses of the widget. */ - useCount: int64; - - /** The number of times the widget was repaired. */ - repairCount: int64; -} - -/** A manufacturer of widgets. */ -@resource("manufacturers") -model Manufacturer { - /** The manufacturer's unique ID. */ - @key("manufacturerId") - @visibility(Lifecycle.Read) - id: string; - - /** The manufacturer's name. */ - name: string; - - /** The manufacturer's full address. */ - address: string; - - ...EtagProperty; -} - -// Operations //////////////////// - -alias ServiceTraits = SupportsRepeatableRequests & - SupportsConditionalRequests & - SupportsClientRequestId; - -alias Operations = Azure.Core.ResourceOperations; - -interface Widgets { - // Operation Status - /** Gets status of a Widget operation. */ - @sharedRoute - getWidgetOperationStatus is Operations.GetResourceOperationStatus; - /** Gets status of a Widget delete operation. */ - @sharedRoute - getWidgetDeleteOperationStatus is Operations.GetResourceOperationStatus; - - // Widget Operations - /** Creates or updates a Widget asynchronously */ - #suppress "@typespec/http/deprecated-implicit-optionality" "Legacy" - @pollingOperation(Widgets.getWidgetOperationStatus) - createOrUpdateWidget is Operations.LongRunningResourceCreateOrUpdate; - - /** Get a Widget */ - getWidget is Operations.ResourceRead; - - /** Delete a Widget asynchronously. */ - @pollingOperation(Widgets.getWidgetDeleteOperationStatus) - deleteWidget is Operations.LongRunningResourceDelete; - - /** List Widget resources */ - listWidgets is Operations.ResourceList< - Widget, - ListQueryParametersTrait - >; - - // Widget Analytics - /** Get a WidgetAnalytics */ - getAnalytics is Operations.ResourceRead; - - /** Creates or updates a WidgetAnalytics */ - #suppress "@typespec/http/deprecated-implicit-optionality" "Legacy" - updateAnalytics is Operations.ResourceCreateOrUpdate; - - // Widget Repair Operations - /** Get the status of a WidgetRepairRequest. */ - #suppress "@azure-tools/typespec-azure-core/use-standard-operations" "This is a custom operation status endpoint." - @route("/widgets/{widgetId}/repairs/{operationId}") - getRepairStatus is Foundations.GetOperationStatus; - - /** Schedule a widget for repairs. */ - @pollingOperation(Widgets.getWidgetOperationStatus) - scheduleRepairs is Operations.LongRunningResourceAction< - Widget, - WidgetRepairRequest, - WidgetRepairRequest & RequestIdResponseHeader - >; -} - -interface WidgetParts { - /** Gets status of a WidgetPart operation. */ - getWidgetPartOperationStatus is Operations.GetResourceOperationStatus; - - /** Creates a WidgetPart */ - createWidgetPart is Operations.ResourceCreateWithServiceProvidedName; - - /** Get a WidgetPart */ - getWidgetPart is Operations.ResourceRead; - - /** Delete a WidgetPart */ - deleteWidgetPart is Operations.ResourceDelete; - - /** List WidgetPart resources */ - listWidgetParts is Operations.ResourceList; - - /** Reorder all parts for the widget. */ - @pollingOperation(WidgetParts.getWidgetPartOperationStatus) - reorderParts is Operations.LongRunningResourceCollectionAction< - WidgetPart, - WidgetPartReorderRequest, - never - >; -} - -interface Manufacturers { - /** Gets status of a Manufacturer operation. */ - getManufacturerOperationStatus is Operations.GetResourceOperationStatus; - - /** Creates or replaces a Manufacturer */ - createOrReplaceManufacturer is Operations.ResourceCreateOrReplace; - - /** Get a Manufacturer */ - getManufacturer is Operations.ResourceRead; - - /** Delete a Manufacturer asynchronously. */ - @pollingOperation(Manufacturers.getManufacturerOperationStatus) - deleteManufacturer is Operations.LongRunningResourceDelete; - - /** List Manufacturer resources */ - listManufacturers is Operations.ResourceList; -} - -// A "global" RPC operation -/** Responds with status information about the overall service. */ -@route("service-status") -op getServiceStatus is RpcOperation< - {}, - { - statusString: string; - }, - ServiceTraits ->; diff --git a/packages/typespec-azure-playground-website/samples/build.js b/packages/typespec-azure-playground-website/samples/build.js deleted file mode 100644 index c927f9004c..0000000000 --- a/packages/typespec-azure-playground-website/samples/build.js +++ /dev/null @@ -1,28 +0,0 @@ -// @ts-check -import { buildSamples_experimental } from "@typespec/playground/tooling"; -import { dirname, resolve } from "path"; -import { fileURLToPath } from "url"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const packageRoot = resolve(__dirname, ".."); - -await buildSamples_experimental(packageRoot, resolve(__dirname, "dist/samples.ts"), { - "Azure Resource Manager framework": { - filename: "samples/arm.tsp", - preferredEmitter: "@azure-tools/typespec-autorest", - description: - "Create Azure Resource Manager (ARM) management-plane APIs using the Azure Resource Manager framework ruleset.", - compilerOptions: { - linterRuleSet: { extends: ["@azure-tools/typespec-azure-rulesets/resource-manager"] }, - }, - }, - "Azure Core Data Plane Service": { - filename: "samples/azure-core.tsp", - preferredEmitter: "@azure-tools/typespec-autorest", - description: - "Model a data-plane service following Azure Core guidelines using the data-plane ruleset.", - compilerOptions: { - linterRuleSet: { extends: ["@azure-tools/typespec-azure-rulesets/data-plane"] }, - }, - }, -}); diff --git a/packages/typespec-azure-playground-website/samples/build.ts b/packages/typespec-azure-playground-website/samples/build.ts new file mode 100644 index 0000000000..fa07a7e86a --- /dev/null +++ b/packages/typespec-azure-playground-website/samples/build.ts @@ -0,0 +1,194 @@ +import type { PlaygroundSample } from "@typespec/playground"; +import { mkdir, readFile, readdir, writeFile } from "fs/promises"; +import { dirname, join, resolve } from "pathe"; +import { fileURLToPath } from "url"; +import { parse as parseYaml } from "yaml"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const samplesSpecsDir = resolve(__dirname, "../../samples/specs"); +const outputFile = resolve(__dirname, "dist/samples.ts"); + +/** Convert a directory name like "data-plane" or "resource-manager" to a display label. */ +function formatCategory(dirName: string): string { + return dirName + .split("-") + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(" "); +} + +interface SampleConfig { + title?: string; + description?: string; + directory?: boolean; + /** Whether to include this sample in the playground. Defaults to true. */ + playground?: boolean; + /** Sort order within a category. Lower values appear first. Defaults to Infinity. */ + order?: number; +} + +interface TspConfig { + emit?: string[]; + linter?: { + extends?: string[]; + }; +} + +async function findSampleConfigs(dir: string): Promise { + const results: string[] = []; + const entries = await readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + results.push(...(await findSampleConfigs(fullPath))); + } else if (entry.name === "sample-config.yaml") { + results.push(fullPath); + } + } + return results; +} + +/** Check if any ancestor directory config has playground: false. */ +async function isPlaygroundExcludedByParent(sampleDir: string, specsDir: string): Promise { + let dir = dirname(sampleDir); + while (dir.startsWith(specsDir)) { + const configPath = join(dir, "sample-config.yaml"); + try { + const content = await readFile(configPath, "utf-8"); + const config = parseYaml(content) as SampleConfig; + if (config.playground === false) return true; + } catch { + // No config at this level + } + const parent = dirname(dir); + if (parent === dir) break; + dir = parent; + } + return false; +} + +/** Find the nearest tspconfig.yaml by walking up the directory tree, stopping at specsDir. */ +async function findNearestTspConfig( + sampleDir: string, + specsDir: string, +): Promise { + let dir = sampleDir; + while (dir.startsWith(specsDir)) { + const configPath = join(dir, "tspconfig.yaml"); + try { + const content = await readFile(configPath, "utf-8"); + return parseYaml(content) as TspConfig; + } catch { + // No config at this level, walk up + } + const parent = dirname(dir); + if (parent === dir) break; + dir = parent; + } + return undefined; +} + +async function findTspFiles(dir: string): Promise { + const results: string[] = []; + const entries = await readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + results.push(...(await findTspFiles(fullPath))); + } else if (entry.name.endsWith(".tsp")) { + results.push(fullPath); + } + } + return results; +} + +// Discover all sample-config.yaml files +const configPaths = (await findSampleConfigs(samplesSpecsDir)).sort(); + +interface CollectedSample { + title: string; + order: number; + sample: PlaygroundSample; +} + +const collected: CollectedSample[] = []; + +for (const configPath of configPaths) { + const sampleDir = dirname(configPath); + const configContent = await readFile(configPath, "utf-8"); + const config = parseYaml(configContent) as SampleConfig; + + // Skip directory-only configs + if (config.directory === true) continue; + + // Skip samples excluded from playground (directly or via parent directory) + if (config.playground === false) continue; + if (await isPlaygroundExcludedByParent(sampleDir, samplesSpecsDir)) continue; + + if (!config.title) { + throw new Error(`Sample config at ${configPath} is missing title field.`); + } + + // Find the nearest tspconfig.yaml for compiler options + const tspConfig = await findNearestTspConfig(sampleDir, samplesSpecsDir); + + // Derive compiler options from tspconfig + let compilerOptions: { linterRuleSet: { extends: string[] } } | undefined; + if (tspConfig?.linter?.extends) { + compilerOptions = { + linterRuleSet: { extends: tspConfig.linter.extends }, + }; + } + + // Derive preferred emitter from tspconfig + const preferredEmitter = tspConfig?.emit?.[0] ?? "@azure-tools/typespec-autorest"; + + // Read all .tsp files for this sample + const tspFiles = (await findTspFiles(sampleDir)).sort(); + const mainTspPath = join(sampleDir, "main.tsp"); + + if (!tspFiles.includes(mainTspPath)) { + throw new Error(`Sample at ${sampleDir} is missing main.tsp file.`); + } + + // Skip multi-file samples — the playground only supports single-file editing + if (tspFiles.length > 1) continue; + + const content = await readFile(mainTspPath, "utf-8"); + + // Compute relative path from specs dir for the sample identifier + const sampleRelPath = sampleDir.slice(samplesSpecsDir.length + 1); + + // Derive category from directory structure (e.g., "data-plane/widget-manager" → "Data Plane") + const pathParts = sampleRelPath.split("/"); + const category = formatCategory(pathParts[0]); + + collected.push({ + title: config.title, + order: config.order ?? Infinity, + sample: { + filename: `../samples/specs/${sampleRelPath}/main.tsp`, + content, + preferredEmitter, + category, + description: config.description ?? "", + ...(compilerOptions ? { compilerOptions } : {}), + }, + }); +} + +// Sort by order within each category so lower-ordered samples appear first +collected.sort((a, b) => a.order - b.order); + +const samples: Record = {}; +for (const { title, sample } of collected) { + samples[title] = sample; +} + +// Write output +await mkdir(dirname(outputFile), { recursive: true }); +const output = [ + `import type { PlaygroundSample } from "@typespec/playground";`, + `const samples: Record = ${JSON.stringify(samples, null, 2)};`, + `export default samples;`, +].join("\n"); +await writeFile(outputFile, output); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c810e8f5ca..64f287d1cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3428,6 +3428,9 @@ importers: vite: specifier: 'catalog:' version: 8.0.8(@types/node@25.5.2)(esbuild@0.28.0)(tsx@4.21.0)(yaml@2.8.3) + yaml: + specifier: 'catalog:' + version: 2.8.3 devDependencies: '@playwright/test': specifier: 'catalog:' @@ -3456,6 +3459,9 @@ importers: cross-env: specifier: 'catalog:' version: 10.1.0 + pathe: + specifier: 'catalog:' + version: 2.0.3 rimraf: specifier: 'catalog:' version: 6.1.3 @@ -14423,11 +14429,6 @@ packages: engines: {node: '>= 14'} hasBin: true - yaml@2.8.2: - resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} - engines: {node: '>= 14.6'} - hasBin: true - yaml@2.8.3: resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} engines: {node: '>= 14.6'} @@ -15360,7 +15361,7 @@ snapshots: smol-toml: 1.6.0 source-map-support: 0.5.21 std-env: 3.10.0 - yaml: 2.8.2 + yaml: 2.8.3 yargs: 18.0.0 zod: 4.3.6 transitivePeerDependencies: @@ -20510,7 +20511,7 @@ snapshots: algoliasearch: 4.27.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) diff: 5.2.2 - ink: 3.2.0(@types/react@19.2.14)(react@19.2.5) + ink: 3.2.0(@types/react@19.2.14)(react@17.0.2) ink-text-input: 4.0.3(ink@3.2.0(@types/react@19.2.14)(react@17.0.2))(react@17.0.2) react: 17.0.2 semver: 7.7.4 @@ -20675,7 +20676,7 @@ snapshots: '@yarnpkg/plugin-git': 3.1.4(@yarnpkg/core@4.6.0(typanion@3.14.0))(typanion@3.14.0) clipanion: 4.0.0-rc.4(typanion@3.14.0) es-toolkit: 1.45.1 - ink: 3.2.0(@types/react@19.2.14)(react@17.0.2) + ink: 3.2.0(@types/react@19.2.14)(react@19.2.5) react: 17.0.2 semver: 7.7.4 tslib: 2.8.1 @@ -27882,8 +27883,6 @@ snapshots: yaml@2.7.1: {} - yaml@2.8.2: {} - yaml@2.8.3: {} yargs-parser@21.1.1: {}