diff --git a/.yarn/versions/92c64300.yml b/.yarn/versions/92c64300.yml new file mode 100644 index 000000000000..99c2d8e32380 --- /dev/null +++ b/.yarn/versions/92c64300.yml @@ -0,0 +1,2 @@ +releases: + "@yarnpkg/sdks": minor diff --git a/packages/docusaurus/docs/getting-started/extra/editor-sdks.mdx b/packages/docusaurus/docs/getting-started/extra/editor-sdks.mdx index 7be5860a6ce4..2aa2b8b846b5 100644 --- a/packages/docusaurus/docs/getting-started/extra/editor-sdks.mdx +++ b/packages/docusaurus/docs/getting-started/extra/editor-sdks.mdx @@ -50,6 +50,8 @@ The `yarn dlx @yarnpkg/sdks` command will look at the content of your *root* `pa | [vscode-eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) | [eslint](https://yarnpkg.com/package/eslint) | | [prettier-vscode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) | [prettier](https://yarnpkg.com/package/prettier) | | [relay](https://marketplace.visualstudio.com/items?itemName=meta.relay) | [relay](https://relay.dev/) +| [oxc](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode) | [oxlint](https://yarnpkg.com/package/oxlint) +| [oxc](https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode) | [oxfmt](https://yarnpkg.com/package/oxfmt) If you'd like to contribute more, [take a look here!](https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-sdks/sources/generateSdk.ts) diff --git a/packages/yarnpkg-sdks/sources/generateSdk.ts b/packages/yarnpkg-sdks/sources/generateSdk.ts index abdd75b2530e..b37ae242ce81 100644 --- a/packages/yarnpkg-sdks/sources/generateSdk.ts +++ b/packages/yarnpkg-sdks/sources/generateSdk.ts @@ -145,6 +145,9 @@ const TEMPLATE = (relPnpApiPath: PortablePath, module: string, {setupEnv = false `\n`, ` process.env.NODE_OPTIONS = process.env.NODE_OPTIONS || \`\`;\n`, ` process.env.NODE_OPTIONS += \` -r \${absPnpApiPath}\`;\n`, + ` if (isPnpLoaderEnabled && register) {\n`, + ` process.env.NODE_OPTIONS += \` --experimental-loader \${pathToFileURL(absPnpLoaderPath)}\`;\n`, + ` }\n`, ` }\n`, ] : []), ...(usePnpify ? [ @@ -201,7 +204,10 @@ export type SupportedSdk = | `typescript-language-server` | `typescript` | `svelte-language-server` - | `flow-bin`; + | `flow-bin` + | `oxfmt` + | `oxlint` + | `oxlint-tsgolint`; export type BaseSdks = Array<[ SupportedSdk, @@ -343,6 +349,21 @@ export class Wrapper { return absWrapperPath; } + async writeRaw(relPackagePath: PortablePath, content: string, options: {mode?: number} = {}) { + const topLevelInformation = this.pnpApi.getPackageInformation(this.pnpApi.topLevel)!; + const projectRoot = npath.toPortablePath(topLevelInformation.packageLocation); + + const absPath = ppath.join(this.target, this.name, relPackagePath); + const relProjectPath = ppath.relative(projectRoot, absPath); + + await xfs.mkdirPromise(ppath.dirname(absPath), {recursive: true}); + await xfs.writeFilePromise(absPath, content, {mode: options.mode}); + + this.paths.set(relPackagePath, relProjectPath); + + return absPath; + } + getProjectPathTo(relPackagePath: PortablePath) { const relProjectPath = this.paths.get(relPackagePath); diff --git a/packages/yarnpkg-sdks/sources/sdks/base.ts b/packages/yarnpkg-sdks/sources/sdks/base.ts index ddbb8855e4a7..12bc145b3012 100644 --- a/packages/yarnpkg-sdks/sources/sdks/base.ts +++ b/packages/yarnpkg-sdks/sources/sdks/base.ts @@ -285,6 +285,67 @@ export const generateFlowBinBaseWrapper: GenerateBaseWrapper = async (pnpApi: Pn return wrapper; }; +export const generateOxfmtBaseWrapper: GenerateBaseWrapper = async (pnpApi: PnpApi, target: PortablePath) => { + const wrapper = new Wrapper(`oxfmt` as PortablePath, {pnpApi, target}); + + const oxfmtMonkeyPatch = ` + module => module; + + const binPath = resolve(absRequire.resolve(\`oxfmt/package.json\`), \`..\`, \`${wrapper.manifest.bin.oxfmt}\`); + absRequire(binPath); + `; + + await wrapper.writeDefaults(); + await wrapper.writeBinary(`bin/oxfmt` as PortablePath, { + setupEnv: true, + requirePath: `` as PortablePath, + wrapModule: oxfmtMonkeyPatch, + }); + + return wrapper; +}; + +export const generateOxlintBaseWrapper: GenerateBaseWrapper = async (pnpApi: PnpApi, target: PortablePath) => { + const wrapper = new Wrapper(`oxlint` as PortablePath, {pnpApi, target}); + + // There are two workarounds here: + // 1. Injecting into PATH to enable tsgolint's PATH resolution strategy in the following tsgolint wrapper. + // 2. Direct file import to work around the top-level await and exports restrictions in oxlint. + const oxlintMonkeyPatch = ` + module => module; + + process.env.PATH += \`;\${resolve(__dirname, \`../../oxlint-tsgolint/bin\`)}\`; + + const binPath = resolve(absRequire.resolve(\`oxlint/package.json\`), \`..\`, \`${wrapper.manifest.bin.oxlint}\`); + import(pathToFileURL(binPath)); + `; + + await wrapper.writeDefaults(); + // This intentionally produces a dummy export; the main logic is in the import above. + // Originally, the binary does not export anything. + await wrapper.writeBinary(`bin/oxlint` as PortablePath, {requirePath: `` as PortablePath, wrapModule: oxlintMonkeyPatch}); + + return wrapper; +}; + +export const generateOxlintTsgolintBaseWrapper: GenerateBaseWrapper = async (pnpApi: PnpApi, target: PortablePath) => { + const wrapper = new Wrapper(`oxlint-tsgolint` as PortablePath, {pnpApi, target}); + + // We are using the oxc_linter tsgolint resolution mechanism via the PATH environment variable + // since it's the only realistic approach to correctly resolve the tsgolint binary when using Yarn PnP. + // Ref: https://github.com/oxc-project/oxc/blob/d3dcf5bc9718ebb4839be27062b5d82da2118e2e/crates/oxc_linter/src/tsgolint.rs#L1164-L1225 + // With this approach, we need to manually create both Unix and Windows executable shim for tsgolint.js. + const tsgolintCmd = ` + @goto #_undefined_# 2>NUL || @title %COMSPEC% & @setlocal & @"node" "%~dp0tsgolint.js" %* + `.trim().replace(/^ {4}/gm, ``); + + await wrapper.writeDefaults(); + await wrapper.writeBinary(`bin/tsgolint` as PortablePath); + await wrapper.writeRaw(`bin/tsgolint.cmd` as PortablePath, tsgolintCmd, {mode: 0o755}); + + return wrapper; +}; + export const BASE_SDKS: BaseSdks = [ [`@astrojs/language-server`, generateAstroLanguageServerBaseWrapper], [`eslint`, generateEslintBaseWrapper], @@ -294,4 +355,7 @@ export const BASE_SDKS: BaseSdks = [ [`typescript`, generateTypescriptBaseWrapper], [`svelte-language-server`, generateSvelteLanguageServerBaseWrapper], [`flow-bin`, generateFlowBinBaseWrapper], + [`oxfmt`, generateOxfmtBaseWrapper], + [`oxlint`, generateOxlintBaseWrapper], + [`oxlint-tsgolint`, generateOxlintTsgolintBaseWrapper], ]; diff --git a/packages/yarnpkg-sdks/sources/sdks/cocvim.ts b/packages/yarnpkg-sdks/sources/sdks/cocvim.ts index a07b6658df54..177f32d671e2 100644 --- a/packages/yarnpkg-sdks/sources/sdks/cocvim.ts +++ b/packages/yarnpkg-sdks/sources/sdks/cocvim.ts @@ -37,7 +37,29 @@ export const generateTypescriptWrapper: GenerateIntegrationWrapper = async (pnpA }); }; +export const generateOxfmtWrapper: GenerateIntegrationWrapper = async (pnpApi: PnpApi, target: PortablePath, wrapper: Wrapper) => { + await addCocVimWorkspaceConfiguration(pnpApi, CocVimConfiguration.settings, { + [`oxc.oxfmt.binPath`]: npath.fromPortablePath( + wrapper.getProjectPathTo( + ppath.normalize(wrapper.manifest.bin.oxfmt), + ), + ), + }); +}; + +export const generateOxlintWrapper: GenerateIntegrationWrapper = async (pnpApi: PnpApi, target: PortablePath, wrapper: Wrapper) => { + await addCocVimWorkspaceConfiguration(pnpApi, CocVimConfiguration.settings, { + [`oxc.oxlint.binPath`]: npath.fromPortablePath( + wrapper.getProjectPathTo( + ppath.normalize(wrapper.manifest.bin.oxlint), + ), + ), + }); +}; + export const COC_VIM_SDKS: IntegrationSdks = [ [`eslint`, generateEslintWrapper], [`typescript`, generateTypescriptWrapper], + [`oxfmt`, generateOxfmtWrapper], + [`oxlint`, generateOxlintWrapper], ]; diff --git a/packages/yarnpkg-sdks/sources/sdks/vscode.ts b/packages/yarnpkg-sdks/sources/sdks/vscode.ts index b47880c59fe9..a4776a4b0c03 100644 --- a/packages/yarnpkg-sdks/sources/sdks/vscode.ts +++ b/packages/yarnpkg-sdks/sources/sdks/vscode.ts @@ -139,6 +139,41 @@ export const generateFlowBinWrapper: GenerateIntegrationWrapper = async (pnpApi: }); }; +export const generateOxfmtWrapper: GenerateIntegrationWrapper = async (pnpApi: PnpApi, target: PortablePath, wrapper: Wrapper) => { + await addVSCodeWorkspaceConfiguration(pnpApi, VSCodeConfiguration.settings, { + [`oxc.path.oxfmt`]: npath.fromPortablePath( + wrapper.getProjectPathTo( + ppath.normalize(wrapper.manifest.bin.oxfmt), + ), + ), + }); + + await addVSCodeWorkspaceConfiguration(pnpApi, VSCodeConfiguration.extensions, { + [`recommendations`]: [ + `oxc.oxc-vscode`, + ], + }); +}; + +export const generateOxlintWrapper: GenerateIntegrationWrapper = async (pnpApi: PnpApi, target: PortablePath, wrapper: Wrapper) => { + await addVSCodeWorkspaceConfiguration(pnpApi, VSCodeConfiguration.settings, { + [`oxc.path.oxlint`]: npath.fromPortablePath( + wrapper.getProjectPathTo( + ppath.normalize(wrapper.manifest.bin.oxlint), + ), + ), + }); + + await addVSCodeWorkspaceConfiguration(pnpApi, VSCodeConfiguration.extensions, { + [`recommendations`]: [ + `oxc.oxc-vscode`, + ], + }); +}; + +export const generateOxlintTsgolintWrapper: GenerateIntegrationWrapper = async (pnpApi: PnpApi, target: PortablePath, wrapper: Wrapper) => { +}; + export const VSCODE_SDKS: IntegrationSdks = [ [null, generateDefaultWrapper], [`@astrojs/language-server`, generateAstroLanguageServerWrapper], @@ -149,4 +184,7 @@ export const VSCODE_SDKS: IntegrationSdks = [ [`typescript`, generateTypescriptWrapper], [`svelte-language-server`, generateSvelteLanguageServerWrapper], [`flow-bin`, generateFlowBinWrapper], + [`oxfmt`, generateOxfmtWrapper], + [`oxlint`, generateOxlintWrapper], + [`oxlint-tsgolint`, generateOxlintTsgolintWrapper], ];