Skip to content

Fix package.json dependency migration when moving from Swagger to TypeSpec modular#3811

Open
Copilot wants to merge 9 commits intomainfrom
copilot/update-package-json-dependencies
Open

Fix package.json dependency migration when moving from Swagger to TypeSpec modular#3811
Copilot wants to merge 9 commits intomainfrom
copilot/update-package-json-dependencies

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 4, 2026

When tsp-client runs against an existing Swagger-generated package, it preserves package.json, causing generateMetadata: false. The emitter skips regenerating package.json entirely, leaving AutoRest-specific dependencies in place and causing compile errors in the newly generated modular code.

Background

When migrating a library originally generated by AutoRest (from Swagger) to TypeSpec generation via tsp-client, the existing package.json contains AutoRest-specific dependencies that differ from what the TypeSpec emitter produces. For example:

AutoRest-generated (original):

"@azure/core-client": "^1.9.3"

TypeSpec-generated (expected):

"@azure-rest/core-client": "^2.3.1"

Changes

  • packages/rlc-common/src/metadata/buildPackageFile.tsupdatePackageFile now handles the full Swagger→TypeSpec migration internally:

    • Added AUTOREST_ONLY_DEPS constant listing AutoRest-specific deps (@azure/core-client, @azure/core-tracing, @azure/core-paging)
    • For Azure monorepo modular packages: reads the existing file, detects AutoRest-specific deps (including @azure/core-lro ^2.x), builds AzureMonorepoInfoConfig from the model, calls getAzureMonorepoDependencies, and overwrites dependencies/devDependencies with canonical TypeSpec values
    • The dependencies option in PackageFileOptions accepts format-specific extra deps (e.g. fast-xml-parser) to merge into the canonical set during migration
    • Re-exports getAzureMonorepoDependencies and AzureMonorepoInfoConfig via @azure-tools/rlc-common
  • packages/typespec-ts/src/index.ts — Simplified else if (hasPackageFile) branch: only passes format-specific extra deps (e.g. fast-xml-parser: ^4.5.0 when XML serialization is used) to updatePackageFile; all AutoRest detection and canonical dep resolution is handled inside updatePackageFile

  • packages/rlc-common/test/integration/packageJson.spec.ts — Added tests for:

    • Auto-detection of @azure/core-client and migration to canonical TypeSpec deps
    • Auto-detection of @azure/core-lro ^2.x and migration
    • No-op when no AutoRest deps are present
    • Format-specific extra deps (e.g. fast-xml-parser) merged into canonical set on migration
    • LRO-specific deps included when model has polling operations

Example

Before (Swagger-generated package.json, kept by tsp-client):

{
  "dependencies": {
    "@azure/core-client": "^1.9.3",
    "@azure/core-tracing": "^1.0.0",
    "@azure/core-rest-pipeline": "^1.19.1",
    "tslib": "^2.6.2"
  },
  "devDependencies": {
    "autorest": "catalog:",
    "@types/node": "^18.0.0"
  }
}

After updatePackageFile runs during modular TypeSpec generation:

{
  "dependencies": {
    "@azure-rest/core-client": "^2.3.1",
    "@azure/core-auth": "^1.9.0",
    "@azure/core-rest-pipeline": "^1.20.0",
    "@azure/core-util": "^1.12.0",
    "@azure/logger": "^1.2.0",
    "tslib": "^2.8.1"
  },
  "devDependencies": {
    "@azure-tools/test-credential": "workspace:^",
    "@azure/dev-tool": "workspace:^",
    "@types/node": "catalog:",
    "typescript": "catalog:"
  }
}
Original prompt

This section details on the original issue you should resolve

<issue_title>package.json isn't correctly updated when moving from swagger -> TSP</issue_title>
<issue_description>I noticed this when running a tsp-client locally for an existing package, specifically the package.json had

"@azure/core-client": "^1.9.3",

which caused compile time issues because it was looking for @azure-rest/core-client in the newly generated code. I was able to resolve this by manually replacing the above with:

"@azure-rest/core-client": "^2.3.1",

We have dependencies and devdependencies diffs between autorest-packageJson generator and modular-packageJson generator.
This issue is because tsp-client will not clean-up metadata files, so the option generateMetadata will be false as packageJson exists. So our emitter will not update metadata files.
We need to add an additional step to update these dependencies when @azure/core-client is detected in packageJson in modular generation.</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…e-client when moving from Swagger to TypeSpec modular

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix package.json update when migrating from swagger to TSP Fix package.json dependency migration when moving from Swagger to TypeSpec modular Mar 4, 2026
@kazrael2119
Copy link
Copy Markdown
Member

@copilot when generateMetadata is true, we will call buildPackageFile, in this case, generateMetadata is false, emitter will not run buildPackageFile. so we need additionally update them

…-parser) to updatePackageFile when generateMetadata is false

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 4, 2026

@copilot when generateMetadata is true, we will call buildPackageFile, in this case, generateMetadata is false, emitter will not run buildPackageFile. so we need additionally update ...

Fixed in 9e41525. The else if (hasPackageFile) branch in index.ts now computes and passes the same additional dependencies (@azure/core-util, fast-xml-parser for XML) as the shouldGenerateMetadata branch. updatePackageFile now also accepts and merges those dependencies (without overwriting existing versions), in addition to migrating @azure/core-client@azure-rest/core-client.

@kazrael2119
Copy link
Copy Markdown
Member

@copilot we need to have a check to compare origin packageJson with the one from getAzureMonorepoDependencies function in typespec-ts/src/index.ts, if they are inconsistent, use the one from getAzureMonorepoDependencies

…es canonical set and update inconsistencies

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 4, 2026

@copilot we need to have a check to compare origin packageJson with the one from getAzureMonorepoDependencies function in typespec-ts/src/index.ts, if they are inconsistent, use the one from getAzur...

Done in 1b63394. updatePackageFile now calls getAzureMonorepoDependencies (with the model + any additional deps like fast-xml-parser) to get the canonical expected dependency set, then compares against the existing package.json. Any dep that's missing or has a different version is updated to the canonical version. @azure/core-client (Swagger-only dep) is also removed. The manual @azure/core-util addition in index.ts was removed since it's already included in getAzureMonorepoDependencies.

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
@kazrael2119
Copy link
Copy Markdown
Member

@copilot clean up all changes first.

In this case, the root cause is:

Background

When using tsp-client to generate SDK code from TypeSpec, tsp-client does not clean the entire library directory before generation. As a result, the emitter detects an existing package.json and sets generateMetadata to false, which prevents metadata files (including package.json) from being regenerated.

Problem

When migrating a library originally generated by AutoRest (from Swagger) to TypeSpec generation via tsp-client, the existing package.json contains AutoRest-specific dependencies that differ from what the TypeSpec emitter should produce. For example:

AutoRest-generated (original):

"@azure/core-client": "^1.9.3"

TypeSpec-generated (expected):

"@azure-rest/core-client": "^2.3.1"

Since generateMetadata is false, the emitter skips updating package.json entirely, leaving the outdated AutoRest dependencies in place. This requires manual intervention to correct the dependencies, which is error-prone and tedious.

Expected Behavior

When generateMetadata is false, the emitter should detect AutoRest-specific dependencies in the existing package.json and incrementally replace them with the correct TypeSpec dependencies.

Proposed Solution

  1. Detect AutoRest dependencies — When generateMetadata is false, check whether the existing package.json contains AutoRest-specific dependencies (e.g., @azure/core-client, @azure/core-lro: ^2.x, @azure/core-tracing, @azure/core-paging).

  2. Incremental replacement — If AutoRest dependencies are detected, add a step in updatePackageFile (in rlc-common) to call getAzureMonorepoDependencies to regenerate the correct TypeSpec dependencies and devDependencies, then overwrite the existing ones in package.json. This ensures the dependencies are fully aligned with what TypeSpec would generate, without needing to regenerate the entire package.json.

…index.ts, overwrite with getAzureMonorepoDependencies canonical set

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/6da87dc7-e715-4f35-b121-eda9d3f0b532
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 25, 2026

@copilot clean up all changes first.

In this case, the root cause is:
...

Done in 63c3c0b. Previous approach was cleaned up and re-implemented as proposed:

  • Detection in index.ts: When generateMetadata is false, hasPackageFile is true, and it's an Azure monorepo modular package — reads the existing package.json and checks for AutoRest-specific deps (@azure/core-client, @azure/core-tracing, @azure/core-paging, @azure/core-lro ^2.x) via a AUTOREST_ONLY_DEPS constant.
  • Overwrite via getAzureMonorepoDependencies: If any AutoRest deps are detected, calls getAzureMonorepoDependencies to get the canonical TypeSpec dependencies and devDependencies, then passes them to updatePackageFile for full overwrite.
  • updatePackageFile (rlc-common): Extended to accept devDependencies parameter; when dependencies/devDependencies are provided, overwrites those sections entirely.
  • getAzureMonorepoDependencies and AzureMonorepoInfoConfig are now re-exported from buildPackageFile.ts so they're accessible from @azure-tools/rlc-common.

Comment thread packages/typespec-ts/src/index.ts Outdated
Comment on lines +615 to +643
if (hasAutorestDeps) {
const additionalDependencies: Record<string, string> = {};
if (packageUsesXmlSerialization(dpgContext.sdkPackage)) {
additionalDependencies["fast-xml-parser"] = "^4.5.0";
}
const depConfig: AzureMonorepoInfoConfig = {
name:
rlcClient.options?.packageDetails?.name ??
rlcClient.libraryName,
version:
rlcClient.options?.packageDetails?.version ?? "1.0.0-beta.1",
description:
rlcClient.options?.packageDetails?.description ??
`A generated SDK for ${rlcClient.libraryName}.`,
moduleKind: option.moduleKind ?? "esm",
withTests: option.generateTest === true,
withSamples: option.generateSample === true,
hasLro: hasPollingOperations(rlcClient),
specSource: "TypeSpec",
clientFilePaths: [],
isModularLibrary: true,
...(Object.keys(additionalDependencies).length > 0 && {
dependencies: additionalDependencies
})
};
const {
dependencies: canonicalDeps,
devDependencies: canonicalDevDeps
} = getAzureMonorepoDependencies(depConfig);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot could we move these step under updatePackageFile?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ea7412d. The AutoRest detection steps are now entirely inside updatePackageFile in rlc-common: it reads the existing file, checks for AutoRest-specific deps, builds the AzureMonorepoInfoConfig from the model, and calls getAzureMonorepoDependencies to overwrite dependencies/devDependencies. index.ts is simplified to just pass format-specific extra deps (e.g. fast-xml-parser) and call updatePackageFile as before.

…plify index.ts

Co-authored-by: kazrael2119 <98569699+kazrael2119@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Azure/autorest.typescript/sessions/2f2504b0-1a5b-4c45-9cb3-774f98a4fa5f
Comment thread packages/typespec-ts/src/index.ts
@qiaozha qiaozha marked this pull request as ready for review April 8, 2026 08:44
@xirzec xirzec requested a review from timovv April 10, 2026 19:23
const needsLroUpdate = isAzure && hasLro;
const isAzureMonorepoLib =
isAzureMonorepoPackage(model) && !!model.options?.isModularLibrary;
const needsLroUpdate = isAzure && hasLro && !isAzureMonorepoLib;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to modify needsLroUpdate related logic? isAzureMonorepoLib conflicts with isAzure and needsLroUpdate will never return true.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

package.json isn't correctly updated when moving from swagger -> TSP

3 participants