diff --git a/#scripts/github-actions/New-IssuesFromAppInsightsExceptions.ps1 b/#scripts/github-actions/New-IssuesFromAppInsightsExceptions.ps1 deleted file mode 100644 index 088f63de0..000000000 --- a/#scripts/github-actions/New-IssuesFromAppInsightsExceptions.ps1 +++ /dev/null @@ -1,127 +0,0 @@ -#Requires -Version 6 - -Set-StrictMode -Version 3 -$ErrorActionPreference = 'Stop' - -function Invoke-JsonCommand($command) { - $json = @($command.Invoke()) -join "`n" - if ($LastExitCode -ne 0) { - Write-Error "Command exited with code $LastExitCode" - } - - if ($json.Trim() -eq '') { - return - } - - return ConvertFrom-Json $json -} - -$ExceptionLabel = ":boom: exception" -$CannotReproduceLabel = "✖ cannot reproduce" - -$query = " - exceptions - | where client_Type != 'Browser' - | where type !startswith 'Unbreakable' - | where not (type == 'System.NotSupportedException' and ( - assembly startswith 'SharpLab' - or - outerMessage has 'not supported by SharpLab' - )) - | where outerType !in ( - 'MirrorSharp.Advanced.EarlyAccess.RoslynSourceTextGuardException', - 'MirrorSharp.Advanced.EarlyAccess.RoslynCompilationGuardException', - 'SharpLab.Runtime.Internal.JitGenericAttributeException' - ) - | extend containerType = iif(type == 'System.Exception', extract('Container host repor?ted an error:[\\r\\n]*([^:]+)', 1, outerMessage), '') - | where containerType != 'SharpLab.Container.Manager.Internal.ContainerAllocationException' - | extend containerMethod = iif(isnotempty(containerType), extract('[\\r\\n]+\\s*at ([^(]+)', 1, outerMessage), '') - | project itemCount, - app=tostring(customDimensions['Web App']), - type=coalesce(containerType, type), - method=iif(type != 'System.InvalidProgramException', coalesce(containerMethod, method), ''), - query=strcat( - 'exceptions\n | where type == \'', type, - iif(type != 'System.InvalidProgramException', strcat('\'\n | where method == \'', method, '\''), ''), - iif(isnotempty(containerType), strcat('\n | where outerMessage contains \'', containerType, '\''), '') - ) - | summarize _count=sum(itemCount) by type, method, query, app - | summarize counts=make_list(pack('app', app, 'count', _count), 100) by type, method, query - | take 150 -" -replace '\s+',' ' - -# Cannot use AZ PowerShell due to login performance issue -# https://github.com/Azure/login/issues/20 -Write-Host 'Getting exceptions from App Insights' -$exceptions = (Invoke-JsonCommand { - az monitor app-insights query ` - --analytics-query $query ` - --apps sharplab-insights ` - --resource-group SharpLab ` - --offset 24h -}).tables[0].rows - -Write-Host 'Getting current issues from GitHub' -$issues = @(Invoke-JsonCommand { - gh issue list --label $ExceptionLabel --json title,url,number,labels,state --state all --limit 500 -}) - -Write-Host 'Processing exceptions' -$exceptions | % { - $exceptionType = $_[0] - $atMethod = $_[1] - $query = $_[2] - $counts = (ConvertFrom-Json $_[3]) - - $title = "$exceptionType at $atMethod" - Write-Host " $title" - $existing = $issues | ? { $_.title -eq $title } - if (!$existing) { - $body = (" - AppInsights query: - ``````Kusto - $query - `````` - " -replace ' ','').Trim() - - Write-Host " - creating" - $url = $(gh issue create --title $title --body $body --label $ExceptionLabel) - if ($LastExitCode -ne 0) { - Write-Error "Command exited with code $LastExitCode" - } - Write-Host " - $url" - $issueNumber = $(Invoke-JsonCommand { - gh issue view $url --json number - }).number - } - else { - Write-Host " - found at $($existing.url)" - $issueNumber = $existing.number - $isClosedAsNotReproducible = $existing.state -eq 'CLOSED' ` - -and $existing.labels ` - -and ($existing.labels | ? { $_.name -eq $CannotReproduceLabel }) - if ($isClosedAsNotReproducible) { - Write-Host " - reopening" - gh issue reopen $issueNumber - if ($LastExitCode -ne 0) { - Write-Error "Command exited with code $LastExitCode" - } - Write-Host " - removing $CannotReproduceLabel" - gh issue edit $issueNumber --remove-label $CannotReproduceLabel - if ($LastExitCode -ne 0) { - Write-Error "Command exited with code $LastExitCode" - } - } - } - - $comment = "| App | Count (last 24h) |`n| ------------- | ------------- |`n" + - (($counts | Sort-Object 'app' | % { "| $($_.app) | $($_.count) |" }) -join "`n") + - "`n| Total | $(($counts | Measure-Object 'count' -Sum).Sum) |" - - Write-Host " - commenting" - $commentUrl = (gh issue comment $issueNumber --body $comment) - if ($LastExitCode -ne 0) { - Write-Error "Command exited with code $LastExitCode" - } - Write-Host " - $commentUrl" -} \ No newline at end of file diff --git a/#scripts/roslyn-branches.ps1 b/#scripts/roslyn-branches.ps1 index 2ec55e6ef..91553753d 100644 --- a/#scripts/roslyn-branches.ps1 +++ b/#scripts/roslyn-branches.ps1 @@ -1,18 +1,28 @@ Set-StrictMode -Version 2.0 $ErrorActionPreference = 'Stop' +$MatricesPath = './!matrices.txt' + Push-Location "$PSScriptRoot/roslyn-branches" try { - $matrix = $null - npm run generate-run-matrix | % { - Write-Host $_ - if ($_ -match '^::set-output name=matrix::(.+)') { - $matrix = ConvertFrom-Json $matches[1] - Write-Host "" - Write-Host "[matrix captured by roslyn-branches.ps1]" -ForegroundColor DarkCyan - } + npm run check + + if (Test-Path $MatricesPath) { + Remove-Item $MatricesPath } + $env:GITHUB_OUTPUT=$MatricesPath + + npm run generate-matrix + $matrices = Get-Content $MatricesPath -Raw + $matrices -match 'update=(.+)' | Out-Null; $update = (ConvertFrom-Json $matches[1]).include + $matrices -match 'cleanup=(.+)' | Out-Null; $cleanup = (ConvertFrom-Json $matches[1]).include + $update + $cleanup + + # TODO: new processing + + <# $matrix.include | % { $row = $_ try { @@ -25,7 +35,7 @@ try { } Write-Error "Branch $($row.branch) failed: $_" } - } + }#> } finally { Pop-Location diff --git a/#scripts/roslyn-branches/.vscode/settings.json b/#scripts/roslyn-branches/.vscode/settings.json index 7cdd25ffd..11c668a89 100644 --- a/#scripts/roslyn-branches/.vscode/settings.json +++ b/#scripts/roslyn-branches/.vscode/settings.json @@ -1,6 +1,6 @@ { "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, "typescript.tsdk": "node_modules\\typescript\\lib", "cSpell.words": [ diff --git a/#scripts/roslyn-branches/arm/parameters.json b/#scripts/roslyn-branches/arm/parameters.json index 9a883ceea..1603e1398 100644 --- a/#scripts/roslyn-branches/arm/parameters.json +++ b/#scripts/roslyn-branches/arm/parameters.json @@ -10,9 +10,6 @@ }, "vaults_name": { "value": "sharplab" - }, - "components_insights_name": { - "value": "sharplab-insights" } } } \ No newline at end of file diff --git a/#scripts/roslyn-branches/arm/template.json b/#scripts/roslyn-branches/arm/template.json index a98b83d06..e417c3349 100644 --- a/#scripts/roslyn-branches/arm/template.json +++ b/#scripts/roslyn-branches/arm/template.json @@ -13,9 +13,6 @@ }, "serverfarms_main_name": { "type": "String" - }, - "components_insights_name": { - "type": "String" } }, "variables": { @@ -37,7 +34,7 @@ "serverFarmId": "[variables('serverfarms_main_id')]", "clientAffinityEnabled": false, "siteConfig": { - "netFrameworkVersion": "v6.0", + "netFrameworkVersion": "v9.0", "publishingUsername": "[concat('$', parameters('sites_name'))]", "use32BitWorkerProcess": true, "webSocketsEnabled": true, @@ -49,10 +46,6 @@ "name": "SHARPLAB_WEBAPP_NAME", "value": "[parameters('sites_name')]" }, - { - "name": "SHARPLAB_TELEMETRY_KEY", - "value": "[reference(resourceId('Microsoft.Insights/components', parameters('components_insights_name')), '2015-05-01', 'Full').properties.InstrumentationKey]" - }, { "name": "SHARPLAB_CONTAINER_HOST_URL", "value": "[parameters('sites_container_host_url')]" diff --git a/#scripts/roslyn-branches/flow/cleanup/cleanupBranch.ts b/#scripts/roslyn-branches/flow/cleanup/cleanupBranch.ts new file mode 100644 index 000000000..58b439623 --- /dev/null +++ b/#scripts/roslyn-branches/flow/cleanup/cleanupBranch.ts @@ -0,0 +1,92 @@ +import { WebSiteManagementClient } from '@azure/arm-appservice'; +import { AZURE_RESOURCE_GROUP_NAME } from '../../shared/azureResourceGroupName'; +import { getBranchesJson, updateInBranchesJson } from '../../shared/branchesJson'; +import { getAzureCredentialWithSubscriptionId } from '../../shared/getAzureCredential'; +import { nodeSafeTopLevelAwait } from '../../shared/nodeSafeTopLevelAwait'; +import { safeGetArgument } from '../../shared/safeGetArgument'; +import type { CleanupAction } from '../../shared/types'; +import { useAzure } from '../../shared/useAzure'; + +const branchName = safeGetArgument(0, 'Branch name'); +const action = safeGetArgument>(1, 'Action'); + +const run = async () => { + if (!useAzure) + throw 'Non-Azure cleanup is not supported'; + + if (action === 'fail-not-merged') + throw 'Unsupported state: branch deleted, but not merged.'; + + console.log(`Action: ${action}`); + + console.log(`Finding branch ${branchName} in branches.json...`); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const branch = (await getBranchesJson()).find(b => b.name === branchName)!; + if (branch.kind !== 'roslyn') + throw `Unexpected branch kind: ${branch.kind}.`; + + const isoNow = (new Date()).toISOString(); + if (action === 'mark-as-merged') { + console.log('Updating branches.json...'); + console.log(' merged: true'); + console.log(` mergeDetected: ${isoNow}`); + await updateInBranchesJson({ + ...branch, + merged: true, + mergeDetected: isoNow + }); + return; + } + + if (!branch.merged) + throw `Unexpected attempt to stop or delete non-merged branch.`; + + const { credential, subscriptionId } = await getAzureCredentialWithSubscriptionId(); + const azureWebAppClient = new WebSiteManagementClient(credential, subscriptionId); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const webAppName = branch.url.match(/([^/.]+).azurewebsites.net/)![1]; + + if (action === 'stop') { + console.log(`Stopping web app ${webAppName}...`); + await azureWebAppClient.webApps.stop(AZURE_RESOURCE_GROUP_NAME, webAppName); + + console.log('Updating branches.json...'); + console.log(` sharplab stopped: ${isoNow}`); + await updateInBranchesJson({ + ...branch, + sharplab: { + ...branch.sharplab ?? { supportsUnknownOptions: false }, + stopped: isoNow + } + }); + return; + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (action !== 'delete') { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw `Unsupported action: ${action}`; + } + + if (!branch.sharplab?.stopped) + throw 'Unexpected attempt to delete non-stopped branch.'; + + console.log(`Deleting web app ${webAppName}...`); + await azureWebAppClient.webApps.delete(AZURE_RESOURCE_GROUP_NAME, webAppName); + console.log('Updating branches.json...'); + console.log(` sharplab deleted: ${isoNow}`); + await updateInBranchesJson({ + ...branch, + sharplab: { + ...branch.sharplab, + deleted: isoNow + } + }); + + console.log('Done.'); +}; + +nodeSafeTopLevelAwait(run, e => { + console.error('::error::' + e); + process.exit(1); +}, { timeoutMinutes: 10 }); \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/prepare/cleanup/getCleanupAction.ts b/#scripts/roslyn-branches/flow/prepare/cleanup/getCleanupAction.ts new file mode 100644 index 000000000..1b7211b74 --- /dev/null +++ b/#scripts/roslyn-branches/flow/prepare/cleanup/getCleanupAction.ts @@ -0,0 +1,30 @@ +import { differenceInDays } from 'date-fns'; +import type { CleanupAction, RoslynBranch } from '../../../shared/types'; + +const DAYS_UNTIL_STOP = 3; +const DAYS_UNTIL_DELETE = 7; + +export const getCleanupAction = (branch: RoslynBranch, merged: boolean): CleanupAction => { + if (!merged) + return 'fail-not-merged'; + + if (!branch.merged) + return 'mark-as-merged'; + + const mergeDetected = new Date(branch.mergeDetected); + if (differenceInDays(new Date(), mergeDetected) < DAYS_UNTIL_STOP) + return 'wait'; + + const { sharplab } = branch; + + if (!sharplab?.stopped) + return 'stop'; + + if (sharplab.deleted) + return 'done'; + + if (differenceInDays(new Date(), new Date(sharplab.stopped)) < DAYS_UNTIL_DELETE) + return 'wait'; + + return 'delete'; +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/prepare/prepareBranchMatrices.ts b/#scripts/roslyn-branches/flow/prepare/prepareBranchMatrices.ts new file mode 100644 index 000000000..0800f0060 --- /dev/null +++ b/#scripts/roslyn-branches/flow/prepare/prepareBranchMatrices.ts @@ -0,0 +1,84 @@ +import '../../env'; +import path from 'path'; +import fs from 'fs-extra'; +import chalk from 'chalk'; +import git from 'simple-git'; +import { nodeSafeTopLevelAwait } from '../../shared/nodeSafeTopLevelAwait'; +import type { Branch } from '../../shared/types'; +import { buildRootPath, rootPath } from '../../shared/paths'; +import { getBranchesJson } from '../../shared/branchesJson'; +import { getCleanupAction } from './cleanup/getCleanupAction'; + +const ROSLYN_REPO_URL = 'https://github.com/dotnet/roslyn.git'; +const roslynSourcePath = path.join(buildRootPath, 'sources/dotnet.git'); + +const branchRunFilter = new RegExp(process.env.SL_BRANCH_FILTER ?? ''); + +const isCommitMergedToMain = async (commitHash: string) => { + return (await git(roslynSourcePath).branch([`--contains`, commitHash])).all + .some(b => /^main$/.test(b)); +}; + +const run = async () => { + console.log('Environment:'); + console.log(` Script Root: ${__dirname}`); + console.log(` Root: ${rootPath}`); + console.log(` Roslyn Source: ${roslynSourcePath}`); + console.log(''); + + const config = JSON.parse(await fs.readFile(`${rootPath}/.roslyn-branches.json`, { encoding: 'utf-8' })) as { + include: string; + }; + + console.log(chalk.white('Cloning Roslyn repository...')); + await git().clone(ROSLYN_REPO_URL, roslynSourcePath, ['--bare', '--filter=blob:none']); + + console.log(chalk.white('Getting git branches...')); + const gitBranches = (await git(roslynSourcePath).branchLocal()) + .all + .filter(b => new RegExp(config.include).test(b)); + console.log(''); + + console.log(chalk.white('Getting branches.json...')); + const branchesJson = await getBranchesJson(); + const branchesNotInGit = branchesJson + .filter((j): j is (Branch & { kind: 'roslyn' }) => j.kind === 'roslyn') + .filter(j => !gitBranches.some(b => b === j.name)); + console.log(''); + + console.log(chalk.white('Preparing cleanup info...')); + const cleanup = (await Promise.all(branchesNotInGit.filter(b => branchRunFilter.test(b.name)).map(async branch => { + const merged = branch.merged + ?? await isCommitMergedToMain(branch.commits[0].hash); + const action = getCleanupAction(branch, merged); + + console.log(` ${branch.id} => ${action}`); + return { + branch: branch.name, + action, + optional: (action === 'fail-not-merged') + }; + }))).filter(a => a.action !== 'wait' && a.action !== 'done'); + + console.log(chalk.white('Writing matrices...')); + const buildMatrix = { + include: gitBranches.filter(b => branchRunFilter.test(b)).map(branch => ({ + branch, + optional: (branch !== 'main') + })) + }; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await fs.appendFile(process.env.GITHUB_OUTPUT!, `update=${JSON.stringify(buildMatrix)}\n`); + + const cleanupMatrix = { include: cleanup }; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await fs.appendFile(process.env.GITHUB_OUTPUT!, `cleanup=${JSON.stringify(cleanupMatrix)}\n`); +}; + +nodeSafeTopLevelAwait(run, e => { + console.error('::error::' + e); + const { stack } = (e as { stack?: string }); + if (stack) + console.error(stack); + process.exit(1); +}, { timeoutMinutes: 5 }); \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/update/steps/publish/publishToAzure.ts b/#scripts/roslyn-branches/flow/update/steps/publish/publishToAzure.ts new file mode 100644 index 000000000..6d29a17d1 --- /dev/null +++ b/#scripts/roslyn-branches/flow/update/steps/publish/publishToAzure.ts @@ -0,0 +1,155 @@ +import path from 'path'; +import fs from 'fs-extra'; +import stripJsonComments from 'strip-json-comments'; +import delay from 'delay'; +import { ResourceManagementClient } from '@azure/arm-resources'; +import { WebSiteManagementClient } from '@azure/arm-appservice'; +import AdmZip from 'adm-zip'; +import dateFormat from 'dateformat'; +import { safeFetch } from '../../../../shared/safeFetch'; +import { getAzureCredentialWithSubscriptionId } from '../../../../shared/getAzureCredential'; +import { AZURE_RESOURCE_GROUP_NAME } from '../../../../shared/azureResourceGroupName'; + +const armTemplatesBasePath = path.join(__dirname, '../../../../arm/'); + +const deployZip = async ({ webAppName, zipPath, userName, password }: { + webAppName: string; + zipPath: string; + userName: string; + password: string; +}) => { + const authHeader = { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + 'Authorization': `Basic ${Buffer.from(`${userName}:${password}`).toString('base64')}` + } as const; + + console.log(` ⏱️ ${dateFormat(new Date(), 'HH:MM:ss')}`); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const deploymentUrl = (await safeFetch(`https://${webAppName}.scm.azurewebsites.net/api/zipdeploy?isAsync=true`, { + method: 'POST', + body: fs.createReadStream(zipPath), + headers: { + ...authHeader, + 'Content-Length': (await fs.stat(zipPath)).size.toString() + }, + redirect: 'manual' + })).headers.get('Location')!; + + let deployment: { + id: string; + complete: boolean; + provisioningState: 'Succeeded'|'Failed'; + log_url: string; + }; + process.stdout.write(' '); + try { + do { + process.stdout.write('░'); + await delay(500); + deployment = await (await safeFetch(deploymentUrl, { + headers: { + ...authHeader + } + })).json() as typeof deployment; + } while (!deployment.complete); + + // https://github.com/projectkudu/kudu/issues/2906 + const logUrl = deployment.log_url.replace('/latest/', `/${deployment.id}/`); + if (deployment.provisioningState !== 'Succeeded') + throw new Error(`Deployment state: ${deployment.provisioningState}, logs at ${logUrl}`); + } + catch (e) { + console.log(''); + console.log(` ❌ ${dateFormat(new Date(), 'HH:MM:ss')}`); + throw e; + } + + console.log(''); + console.log(` ✔️ ${dateFormat(new Date(), 'HH:MM:ss')}`); +}; + +export const publishToAzure = async ({ + webAppName, + branchArtifactsRoot, + branchSiteRoot +}: { + webAppName: string; + branchArtifactsRoot: string; + branchSiteRoot: string; +}) => { + const armTemplate = JSON.parse(stripJsonComments( + await fs.readFile(path.join(armTemplatesBasePath, 'template.json'), 'utf-8') + )); + const armParameters = (JSON.parse(await fs.readFile(path.join(armTemplatesBasePath, 'parameters.json'), 'utf-8')) as { + parameters: Record; + }).parameters; + + console.log(`Deploying to Azure, ${webAppName}...`); + + const { credential, subscriptionId } = await getAzureCredentialWithSubscriptionId(); + + const azureResourceClient = new ResourceManagementClient(credential, subscriptionId); + const azureWebAppClient = new WebSiteManagementClient(credential, subscriptionId); + + console.log(` Deploying web app...`); + const result = await azureResourceClient.deployments.beginCreateOrUpdateAndWait( + AZURE_RESOURCE_GROUP_NAME, + webAppName.replace(/^sl-b-/, 'sharplab-branch-'), { + properties: { + mode: 'Incremental', + template: armTemplate, + parameters: { + sites_name: { value: webAppName }, + ...armParameters + } + } + } + ); + const { error } = result.properties ?? {}; + if (error) + throw new Error(`Deployment ${result.id ?? ''} failed with code ${error.code ?? ''}.`); + console.log(` Provisioning: ${result.properties?.provisioningState ?? ''}`); + + console.log(` Zipping...`); + const zipPath = path.join(branchArtifactsRoot, 'Site.zip'); + console.log(` => ${zipPath}`); + const zip = new AdmZip(); + zip.addLocalFolder(branchSiteRoot); + zip.writeZip(zipPath); + + console.log(` Stopping...`); + await azureWebAppClient.webApps.stop(AZURE_RESOURCE_GROUP_NAME, webAppName); + + console.log(` Publishing...`); + const { + publishingUserName, + publishingPassword + } = await azureWebAppClient.webApps.beginListPublishingCredentialsAndWait(AZURE_RESOURCE_GROUP_NAME, webAppName); + + let deployTryCount = 1; + let deployDone = false; + do { + try { + await deployZip({ + webAppName, + zipPath, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + userName: publishingUserName!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + password: publishingPassword! + }); + deployDone = true; + } + catch (e) { + if (deployTryCount >= 3) + throw e; + console.warn(e); + deployTryCount += 1; + } + } while (!deployDone); + + console.log(` Starting...`); + await azureWebAppClient.webApps.start(AZURE_RESOURCE_GROUP_NAME, webAppName); + + console.log(` Done.`); +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/update/steps/publish/testWebApp.ts b/#scripts/roslyn-branches/flow/update/steps/publish/testWebApp.ts new file mode 100644 index 000000000..13eb1b076 --- /dev/null +++ b/#scripts/roslyn-branches/flow/update/steps/publish/testWebApp.ts @@ -0,0 +1,42 @@ +import delay from 'delay'; +import { safeFetch, Response, type SafeFetchError } from '../../../../shared/safeFetch'; + +export const testWebApp = async ({ url }: { url: string }) => { + console.log(`GET ${url}/status`); + let ok = false; + let tryPermanent = 1; + let tryTemporary = 1; + + const formatStatus = ({ status, statusText }: Pick) => + ` ${status} ${statusText}`; + + while (tryPermanent < 3 && tryTemporary < 30) { + try { + const response = await safeFetch(`${url}/status`); + ok = true; + console.log(formatStatus(response)); + break; + } + catch (e) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if ((e as { response?: Response }).response) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + console.warn(formatStatus((e as { response: Response }).response)); + } + + const { status } = (e as Partial).response ?? {}; + const temporary = status === 503 || status === 403 || (e as { code?: string }).code === 'ECONNRESET'; + if (temporary) { + tryTemporary += 1; + } + else { + tryPermanent += 1; + } + console.warn(e); + } + await delay(1000); + } + + if (!ok) + throw new Error(`Failed to get success from ${url}/status`); +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/update/steps/publishBranch.ts b/#scripts/roslyn-branches/flow/update/steps/publishBranch.ts new file mode 100644 index 000000000..bacef0ca7 --- /dev/null +++ b/#scripts/roslyn-branches/flow/update/steps/publishBranch.ts @@ -0,0 +1,25 @@ +import { useAzure } from '../../../shared/useAzure'; +import { publishToAzure } from './publish/publishToAzure'; +import { testWebApp } from './publish/testWebApp'; + +export const publishBranch = async ({ webAppName, webAppUrl, branchArtifactsRoot, branchSiteRoot }: { + webAppName: string; + iisSiteName: string; + webAppUrl: string; + branchArtifactsRoot: string; + branchSiteRoot: string; +}) => { + if (useAzure) { + await publishToAzure({ + webAppName, + branchArtifactsRoot, + branchSiteRoot + }); + } + else { + // TODO: migrate to TypeScript + throw new Error('Not migrated to TypeScript yet.'); + } + + await testWebApp({ url: webAppUrl }); +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/flow/update/steps/publishBranchJson.ts b/#scripts/roslyn-branches/flow/update/steps/publishBranchJson.ts new file mode 100644 index 000000000..aa89c7e56 --- /dev/null +++ b/#scripts/roslyn-branches/flow/update/steps/publishBranchJson.ts @@ -0,0 +1,62 @@ +import fs from 'fs-extra'; +import { buildRootPath } from '../../../shared/paths'; +import { safeFetch } from '../../../shared/safeFetch'; +import type { Branch, Commit } from '../../../shared/types'; +import { updateInBranchesJson } from '../../../shared/branchesJson'; + +const languageFeatureMapUrl = 'https://raw.githubusercontent.com/dotnet/roslyn/main/docs/Language%20Feature%20Status.md'; + +export async function getRoslynBranchFeatureMap() { + const markdown = await (await safeFetch(languageFeatureMapUrl)).text(); + const languageVersions = markdown.matchAll(/#\s*(?.+)\s*$\s*(?(?:^\|.+$\s*)+)/gm); + + const mapPath = `${buildRootPath}/RoslynFeatureMap.json`; + let map = {} as Record; + if (await fs.pathExists(mapPath)) + map = await fs.readJson(mapPath); + + for (const languageMatch of languageVersions) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { language, table } = languageMatch.groups!; + const rows = table.matchAll(/^\|(?[^|]+)\|.+roslyn\/tree\/(?[A-Za-z\d\-/]+)/gm); + + for (const rowMatch of rows) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const { rawName, branch } = rowMatch.groups!; + let name = rawName.trim(); + let url = ''; + const link = name.match(/\[([^\]]+)\]\(([^)]+)\)/); + if (link) + ([, name, url] = link); + + map[branch] = { language, name, url }; + } + } + + await fs.writeFile(mapPath, JSON.stringify(map, null, 2)); + return map; +} + +export default async function publicBranchJson(branch: { + id: string; + name: string; + url: string; + commits: ReadonlyArray; +}) { + const roslynBranchFeatureMap = await getRoslynBranchFeatureMap(); + const feature = roslynBranchFeatureMap[branch.name]; + const branchJson = { + id: branch.id, + name: branch.name, + group: 'Roslyn branches', + kind: 'roslyn', + url: branch.url, + ...(feature ? { feature } : {}), + commits: branch.commits, + sharplab: { + supportsUnknownOptions: true + } + } as Branch; + + await updateInBranchesJson(branchJson); +} \ No newline at end of file diff --git a/#scripts/roslyn-branches/buildBranch.ts b/#scripts/roslyn-branches/flow/update/updateBranch.ts similarity index 81% rename from #scripts/roslyn-branches/buildBranch.ts rename to #scripts/roslyn-branches/flow/update/updateBranch.ts index 97d3bae6f..d90e296e5 100644 --- a/#scripts/roslyn-branches/buildBranch.ts +++ b/#scripts/roslyn-branches/flow/update/updateBranch.ts @@ -1,31 +1,30 @@ -import './env'; +import '../../env'; import stream from 'stream'; import path from 'path'; import { promisify } from 'util'; import fs from 'fs-extra'; import globby from 'globby'; -import git from 'simple-git/promise'; +import git from 'simple-git'; import extract from 'extract-zip'; import execa from 'execa'; import chalk from 'chalk'; -import safeFetch from './helpers/safeFetch'; -import useAzure from './helpers/useAzure'; -import publishBranch from './steps/publishBranch'; -import updateInBranchesJson from './steps/updateInBranchesJson'; +import { safeFetch } from '../../shared/safeFetch'; +import { useAzure } from '../../shared/useAzure'; +import { nodeSafeTopLevelAwait } from '../../shared/nodeSafeTopLevelAwait'; +import { safeGetArgument } from '../../shared/safeGetArgument'; +import { buildRootPath, rootPath } from '../../shared/paths'; +import { publishBranch } from './steps/publishBranch'; +import publishBranchJson from './steps/publishBranchJson'; const pipeline = promisify(stream.pipeline); const branchVersionFileName = 'branch-version.json'; -const branchName = process.argv[2] - ?? (() => { throw new Error('Branch name was not provided'); })(); +const branchName = safeGetArgument(0, 'Branch name'); -const root = path.resolve(`${__dirname}/../..`); -const sourceRoot = path.join(root, 'source'); -const buildRoot = path.join(root, '!roslyn-branches'); -fs.ensureDirSync(buildRoot); +const sourceRoot = path.join(rootPath, 'source'); const branchFSName = 'dotnet-' + branchName.replace(/[/\\:_]/g, '-'); -const branchRoot = path.join(buildRoot, branchFSName); +const branchRoot = path.join(buildRootPath, branchFSName); const branchArtifactsRoot = path.join(branchRoot, 'artifacts'); const branchSiteRoot = path.join(branchRoot, 'site'); @@ -42,9 +41,9 @@ const webAppUrl = useAzure console.log('Environment:'); console.log(` Azure: ${useAzure}`); -console.log(` Root: ${root}`); +console.log(` Root: ${rootPath}`); console.log(` Source Root: ${sourceRoot}`); -console.log(` Build Root: ${buildRoot}`); +console.log(` Build Root: ${buildRootPath}`); console.log(` Branch FS Name: ${branchFSName}`); console.log(` Branch Root: ${branchRoot}`); console.log(` Branch Artifacts Root: ${branchArtifactsRoot}`); @@ -54,7 +53,8 @@ console.log(` Web App URL: ${webAppUrl}`); console.log(''); async function updateRoslynBuildPackages(currentBuildId: string|null) { - const roslynBuildsUrl = `https://dev.azure.com/dnceng/public/_apis/build/builds?api-version=5.0&definitions=15&reasonfilter=individualCI&resultFilter=succeeded&$top=1&branchName=refs/heads/${branchName}`; + // See https://dev.azure.com/dnceng-public/public/_build?definitionId=95 + const roslynBuildsUrl = `https://dev.azure.com/dnceng-public/public/_apis/build/builds?api-version=5.0&definitions=95&reasonfilter=individualCI&resultFilter=succeeded&$top=1&branchName=refs/heads/${branchName}`; const builds = await (await safeFetch(roslynBuildsUrl)).json() as { count: number; value: ReadonlyArray<{ @@ -94,9 +94,20 @@ async function updateRoslynBuildPackages(currentBuildId: string|null) { }; }>; }; - const roslynPackages = roslynArtifacts.value.find(a => a.name === 'Packages - PreRelease'); - if (!roslynPackages) - throw 'Packages were not found in Roslyn Azure build artifacts.'; + if (roslynArtifacts.value.length === 0) + throw `No Roslyn Azure build artifacts found.`; + + const roslynPackages = roslynArtifacts.value.find( + a => a.name === 'Packages - PreRelease' + || a.name === 'Bootstrap Packages - PreRelease' + || a.name === 'Bootstrap Packages - AnyCpu' + || a.name === 'Bootstrap Packages - Default' + ); + if (!roslynPackages) { + throw `Packages were not found in Roslyn Azure build artifacts.\nAvailable artifacts: ${ + roslynArtifacts.value.map(a => `\n* ${a.name}`).join('') + }`; + } const downloadUrl = roslynPackages.resource.downloadUrl; const zipPath = path.join(branchArtifactsRoot, `Packages.${build.id}.zip`); @@ -104,7 +115,7 @@ async function updateRoslynBuildPackages(currentBuildId: string|null) { if (!(await fs.pathExists(zipPath))) { // Optimization for local only console.log(`GET ${downloadUrl} => ${zipPath}`); const response = await safeFetch(downloadUrl); - await pipeline(response.body, fs.createWriteStream(zipPath)); + await pipeline(response.body!, fs.createWriteStream(zipPath)); } else { console.log(`Found cached ${zipPath}, no need to download`); @@ -144,11 +155,13 @@ async function buildSharpLab(roslynPackagesRoot: string) { await fs.ensureDir(branchSourceRoot); console.log('Building Roslyn package map...'); - const roslynVersionMap = Object.fromEntries( (await globby(['*.nupkg'], { cwd: roslynPackagesRoot, absolute: true })).map(filePath => { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const [, name, version] = path.basename(filePath).match(/^([^\d]+)\.(\d.+)\.nupkg$/)!; + const fileName = path.basename(filePath); + const match = fileName.match(/^((?:[^\d.][^.]*\.)*[^\d.][^.]*)\.(\d.+)\.nupkg$/); + if (!match) throw new Error(`Could not parse package file name '${fileName}'`); + + const [, name, version] = match; return [name, version]; }) ); @@ -164,7 +177,7 @@ async function buildSharpLab(roslynPackagesRoot: string) { // sigh: dotnet.exe should do this, but of course it does not const projectPath = projectPathUntyped as string; const projectName = path.basename(projectPath); - if (/mirrorsharp[/\\]Internal\.Roslyn/i.test(projectPath)) { + if (/mirrorsharp[^/\\]*[/\\]Internal\.Roslyn|Mobius\.ILasm\.Tests\.SourceGenerator/i.test(projectPath)) { console.log(` ${projectName}`); console.log(' Skipping'); continue; @@ -209,6 +222,7 @@ async function buildSharpLab(roslynPackagesRoot: string) { '--source', 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json', '--source', 'https://ci.appveyor.com/nuget/vanara-prerelease', '--source', roslynPackagesRoot, + '-p:NuGetAudit=false', '--verbosity', 'minimal' ], { stdout: 'inherit', @@ -229,7 +243,7 @@ async function buildSharpLab(roslynPackagesRoot: string) { }); return { - publishRoot: `${branchSourceRoot}/Server/bin/Release/net6.0/publish` + publishRoot: `${branchSourceRoot}/Server/bin/Release/net9.0/publish` }; } @@ -355,36 +369,7 @@ async function run() { }); console.log(chalk.white('* Listing')); - await updateInBranchesJson({ - buildRoot, - branch: buildResult.info - }); -} - -function nodeSafeTopLevelAwait( - call: () => Promise, - handleError: (e: unknown) => void, - { timeoutMinutes }: { timeoutMinutes: number } -) { - let keepaliveTimer: ReturnType; - // https://github.com/nodejs/node/issues/22088 - const keepalive = () => new Promise((_, reject) => keepaliveTimer = setTimeout( - () => reject(new Error(`Top-level async timed out within ${timeoutMinutes} minutes.`)), timeoutMinutes * 60 * 1000 - )); - - // eslint-disable-next-line @typescript-eslint/no-floating-promises - (async () => { - try { - await Promise.race([call(), keepalive()]); - } - catch (e) { - handleError(e); - } - finally { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - clearTimeout(keepaliveTimer!); - } - })(); + await publishBranchJson(buildResult.info); } nodeSafeTopLevelAwait(run, e => { diff --git a/#scripts/roslyn-branches/generateGitHubRunMatrix.ts b/#scripts/roslyn-branches/generateGitHubRunMatrix.ts deleted file mode 100644 index 5958c5dc3..000000000 --- a/#scripts/roslyn-branches/generateGitHubRunMatrix.ts +++ /dev/null @@ -1,34 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import chalk from 'chalk'; -import execa from 'execa'; - -const root = path.resolve(`${__dirname}/../..`); - -console.log('Environment:'); -console.log(` Script Root: ${__dirname}`); -console.log(` Root: ${root}`); -console.log(''); - -const config = JSON.parse(fs.readFileSync(`${root}/.roslyn-branches.json`, { encoding: 'utf-8' })) as { - include: string; -}; - -console.log(chalk.white('Getting branches...')); -console.log(' git ls-remote --heads https://github.com/dotnet/roslyn.git'); -const { stdout: branchesString } = execa.commandSync('git ls-remote --heads https://github.com/dotnet/roslyn.git'); -const branches = branchesString - .split(/[\r\n]+/g) - .map(b => b.replace(/.*refs\/heads\/(\S+).*$/, '$1')) - .filter(b => new RegExp(config.include).test(b)); -console.log(''); - -console.log(chalk.white('Writing matrix...')); -const matrix = { - include: branches.map(branch => ({ - branch, - optional: (branch !== 'main') - })) -}; - -console.log(`::set-output name=matrix::${JSON.stringify(matrix)}`); \ No newline at end of file diff --git a/#scripts/roslyn-branches/helpers/useAzure.ts b/#scripts/roslyn-branches/helpers/useAzure.ts deleted file mode 100644 index cfd89a80b..000000000 --- a/#scripts/roslyn-branches/helpers/useAzure.ts +++ /dev/null @@ -1 +0,0 @@ -export default process.env.SL_DEPLOY_MODE === 'Azure'; \ No newline at end of file diff --git a/#scripts/roslyn-branches/package-lock.json b/#scripts/roslyn-branches/package-lock.json index 347f8f55b..84ee58c30 100644 --- a/#scripts/roslyn-branches/package-lock.json +++ b/#scripts/roslyn-branches/package-lock.json @@ -1,2829 +1,7442 @@ -{ - "name": "roslyn-branches", - "version": "0.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@azure/abort-controller": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.1.tgz", - "integrity": "sha512-wP2Jw6uPp8DEDy0n4KNidvwzDjyVV2xnycEIq7nPzj1rHyb/r+t3OPeNT1INZePP2wy5ZqlwyuyOMTi0ePyY1A==", - "requires": { - "tslib": "^1.9.3" - } - }, - "@azure/arm-appservice": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@azure/arm-appservice/-/arm-appservice-6.0.0.tgz", - "integrity": "sha512-kAr/Xjx5FQ+cFdSE21kHP4ZuQrc6kwCH21vI8ccYwZKG9IIgpoJ4arDnjucTWGpIOBgB5h06xT5nePN+qZNgoQ==", - "requires": { - "@azure/ms-rest-azure-js": "^2.0.1", - "@azure/ms-rest-js": "^2.0.4", - "tslib": "^1.10.0" - } - }, - "@azure/arm-authorization": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/@azure/arm-authorization/-/arm-authorization-8.3.3.tgz", - "integrity": "sha512-CcsUxidMRmioLqFapshYxg3g12A6NUdCnfVARPzxH61Tz5FqATfLDzdSIoLT2EfuKkjA/jEWzkFvoBbNaWBUNA==", - "requires": { - "@azure/ms-rest-azure-js": "^2.0.0", - "@azure/ms-rest-js": "^2.0.3", - "tslib": "^1.9.3" - } - }, - "@azure/arm-resources": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@azure/arm-resources/-/arm-resources-2.1.0.tgz", - "integrity": "sha512-WpBQt3QwfulWAgss7r6apfKswc6SS8Z005AhQalx618757dX+0kTiizL5XipDZFWq/nlCN2fFv9ba1m4v5x2tg==", - "requires": { - "@azure/ms-rest-azure-js": "^2.0.1", - "@azure/ms-rest-js": "^2.0.4", - "tslib": "^1.10.0" - } - }, - "@azure/core-asynciterator-polyfill": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@azure/core-asynciterator-polyfill/-/core-asynciterator-polyfill-1.0.0.tgz", - "integrity": "sha512-kmv8CGrPfN9SwMwrkiBK9VTQYxdFQEGe0BmQk+M8io56P9KNzpAxcWE/1fxJj7uouwN4kXF0BHW8DNlgx+wtCg==" - }, - "@azure/core-auth": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.1.2.tgz", - "integrity": "sha512-IUbP/f3v96dpHgXUwsAjUwDzjlUjawyUhWhGKKB6Qxy+iqppC/pVBPyc6kdpyTe7H30HN+4H3f0lar7Wp9Hx6A==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-tracing": "1.0.0-preview.8", - "@opentelemetry/api": "^0.6.1", - "tslib": "^1.10.0" - }, - "dependencies": { - "@azure/core-tracing": { - "version": "1.0.0-preview.8", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.8.tgz", - "integrity": "sha512-ZKUpCd7Dlyfn7bdc+/zC/sf0aRIaNQMDuSj2RhYRFe3p70hVAnYGp3TX4cnG2yoEALp/LTj/XnZGQ8Xzf6Ja/Q==", - "requires": { - "@opencensus/web-types": "0.0.7", - "@opentelemetry/api": "^0.6.1", - "tslib": "^1.10.0" - } - } - } - }, - "@azure/core-http": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-http/-/core-http-1.1.2.tgz", - "integrity": "sha512-xeZpTs6caBIrRipqZs70jgrA+mAFxII5XrBzbOCELPs18n4QWfchB20F94ITAk3GuFVDaSBsOhVL3GP1J+ncGg==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-auth": "^1.1.2", - "@azure/core-tracing": "1.0.0-preview.8", - "@azure/logger": "^1.0.0", - "@opentelemetry/api": "^0.6.1", - "@types/node-fetch": "^2.5.0", - "@types/tunnel": "^0.0.1", - "cross-env": "^6.0.3", - "form-data": "^3.0.0", - "node-fetch": "^2.6.0", - "process": "^0.11.10", - "tough-cookie": "^3.0.1", - "tslib": "^1.10.0", - "tunnel": "^0.0.6", - "uuid": "^3.3.2", - "xml2js": "^0.4.19" - }, - "dependencies": { - "@azure/core-tracing": { - "version": "1.0.0-preview.8", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.8.tgz", - "integrity": "sha512-ZKUpCd7Dlyfn7bdc+/zC/sf0aRIaNQMDuSj2RhYRFe3p70hVAnYGp3TX4cnG2yoEALp/LTj/XnZGQ8Xzf6Ja/Q==", - "requires": { - "@opencensus/web-types": "0.0.7", - "@opentelemetry/api": "^0.6.1", - "tslib": "^1.10.0" - } - }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@azure/core-lro": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-1.0.2.tgz", - "integrity": "sha512-Yr0JD7GKryOmbcb5wHCQoQ4KCcH5QJWRNorofid+UvudLaxnbCfvKh/cUfQsGUqRjO9L/Bw4X7FP824DcHdMxw==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^1.1.1", - "events": "^3.0.0", - "tslib": "^1.10.0" - } - }, - "@azure/core-paging": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.1.1.tgz", - "integrity": "sha512-hqEJBEGKan4YdOaL9ZG/GRG6PXaFd/Wb3SSjQW4LWotZzgl6xqG00h6wmkrpd2NNkbBkD1erLHBO3lPHApv+iQ==", - "requires": { - "@azure/core-asynciterator-polyfill": "^1.0.0" - } - }, - "@azure/core-tracing": { - "version": "1.0.0-preview.7", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.0-preview.7.tgz", - "integrity": "sha512-pkFCw6OiJrpR+aH1VQe6DYm3fK2KWCC5Jf3m/Pv1RxF08M1Xm08RCyQ5Qe0YyW5L16yYT2nnV48krVhYZ6SGFA==", - "requires": { - "@opencensus/web-types": "0.0.7", - "@opentelemetry/types": "^0.2.0", - "tslib": "^1.9.3" - } - }, - "@azure/logger": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.0.tgz", - "integrity": "sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA==", - "requires": { - "tslib": "^1.9.3" - } - }, - "@azure/ms-rest-azure-env": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-env/-/ms-rest-azure-env-2.0.0.tgz", - "integrity": "sha512-dG76W7ElfLi+fbTjnZVGj+M9e0BIEJmRxU6fHaUQ12bZBe8EJKYb2GV50YWNaP2uJiVQ5+7nXEVj1VN1UQtaEw==" - }, - "@azure/ms-rest-azure-js": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-azure-js/-/ms-rest-azure-js-2.0.1.tgz", - "integrity": "sha512-5e+A710O7gRFISoV4KI/ZyLQbKmjXxQZ1L8Z/sx7jSUQqmswjTnN4yyIZxs5JzfLVkobU0rXxbi5/LVzaI8QXQ==", - "requires": { - "@azure/ms-rest-js": "^2.0.4", - "tslib": "^1.10.0" - } - }, - "@azure/ms-rest-js": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-js/-/ms-rest-js-2.0.7.tgz", - "integrity": "sha512-rQpNxDhyOIyS4E+4sUCBMvjrtbNwB32wH06cC2SFoQM4TR29bIKaTlIC1tMe0K07w9c5tNk/2uUHs6/ld/Z3+A==", - "requires": { - "@types/node-fetch": "^2.3.7", - "@types/tunnel": "0.0.1", - "abort-controller": "^3.0.0", - "form-data": "^2.5.0", - "node-fetch": "^2.6.0", - "tough-cookie": "^3.0.1", - "tslib": "^1.10.0", - "tunnel": "0.0.6", - "uuid": "^3.3.2", - "xml2js": "^0.4.19" - } - }, - "@azure/ms-rest-nodeauth": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@azure/ms-rest-nodeauth/-/ms-rest-nodeauth-3.0.3.tgz", - "integrity": "sha512-/KAgVV68vkOdrx6O3T6qO7thCep4nPbWzkpNIPFN3P6uzEzDIk6BCGgkzabnmkb2kXaf4+IGHs0UMoXSfN/IgQ==", - "requires": { - "@azure/ms-rest-azure-env": "^2.0.0", - "@azure/ms-rest-js": "^2.0.4", - "adal-node": "^0.1.28" - } - }, - "@azure/storage-blob": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.1.1.tgz", - "integrity": "sha512-FhzXfrPe5DZE5KNbFoKXXhGqX362I+dGv0jVINCCQiToqadROZ1tRFtJ3ljnMPs75fZZzwnbq+oIB6NnpBqOzA==", - "requires": { - "@azure/abort-controller": "^1.0.0", - "@azure/core-http": "^1.0.3", - "@azure/core-lro": "^1.0.0", - "@azure/core-paging": "^1.1.0", - "@azure/core-tracing": "1.0.0-preview.7", - "@azure/logger": "^1.0.0", - "@opentelemetry/types": "^0.2.0", - "events": "^3.0.0", - "tslib": "^1.10.0" - } - }, - "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.8.3" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", - "dev": true - }, - "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.9.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "@kwsites/exec-p": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@kwsites/exec-p/-/exec-p-0.4.0.tgz", - "integrity": "sha512-44DWNv5gDR9EwrCTVQ4ZC99yPqVS0VCWrYIBl45qNR8XQy+4lbl0IQG8kBDf6NHwj4Ib4c2z1Fq1IUJOCbkZcw==" - }, - "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", - "requires": { - "@nodelib/fs.stat": "2.0.3", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==" - }, - "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", - "requires": { - "@nodelib/fs.scandir": "2.1.3", - "fastq": "^1.6.0" - } - }, - "@opencensus/web-types": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@opencensus/web-types/-/web-types-0.0.7.tgz", - "integrity": "sha512-xB+w7ZDAu3YBzqH44rCmG9/RlrOmFuDPt/bpf17eJr8eZSrLt7nc7LnWdxM9Mmoj/YKMHpxRg28txu3TcpiL+g==" - }, - "@opentelemetry/api": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.6.1.tgz", - "integrity": "sha512-wpufGZa7tTxw7eAsjXJtiyIQ42IWQdX9iUQp7ACJcKo1hCtuhLU+K2Nv1U6oRwT1oAlZTE6m4CgWKZBhOiau3Q==", - "requires": { - "@opentelemetry/context-base": "^0.6.1" - } - }, - "@opentelemetry/context-base": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.6.1.tgz", - "integrity": "sha512-5bHhlTBBq82ti3qPT15TRxkYTFPPQWbnkkQkmHPtqiS1XcTB69cEKd3Jm7Cfi/vkPoyxapmePE9tyA7EzLt8SQ==" - }, - "@opentelemetry/types": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/types/-/types-0.2.0.tgz", - "integrity": "sha512-GtwNB6BNDdsIPAYEdpp3JnOGO/3AJxjPvny53s3HERBdXSJTGQw8IRhiaTEX0b3w9P8+FwFZde4k+qkjn67aVw==" - }, - "@types/adm-zip": { - "version": "0.4.33", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz", - "integrity": "sha512-WM0DCWFLjXtddl0fu0+iN2ZF+qz8RF9RddG5OSy/S90AQz01Fu8lHn/3oTIZDxvG8gVcnBLAHMHOdBLbV6m6Mw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, - "@types/dateformat": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz", - "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==", - "dev": true - }, - "@types/eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==", - "dev": true - }, - "@types/fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-xCbDUSZArlmMjiJdczt8AFNH2MwcMb/pj/HKja1hx3u1qzOUINcJktQMGoGVlgFnzxnuCahxKFlcRBkSAcm33g==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/json-schema": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", - "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==", - "dev": true - }, - "@types/node": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.1.tgz", - "integrity": "sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==" - }, - "@types/node-fetch": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz", - "integrity": "sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==", - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - }, - "dependencies": { - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - } - } - }, - "@types/tunnel": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@types/tunnel/-/tunnel-0.0.1.tgz", - "integrity": "sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A==", - "requires": { - "@types/node": "*" - } - }, - "@types/yargs": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", - "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", - "dev": true - }, - "@types/yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "2.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.33.0.tgz", - "integrity": "sha512-QV6P32Btu1sCI/kTqjTNI/8OpCYyvlGjW5vD8MpTIg+HGE5S88HtT1G+880M4bXlvXj/NjsJJG0aGcVh0DdbeQ==", - "dev": true, - "requires": { - "@typescript-eslint/experimental-utils": "2.33.0", - "functional-red-black-tree": "^1.0.1", - "regexpp": "^3.0.0", - "tsutils": "^3.17.1" - } - }, - "@typescript-eslint/experimental-utils": { - "version": "2.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.33.0.tgz", - "integrity": "sha512-qzPM2AuxtMrRq78LwyZa8Qn6gcY8obkIrBs1ehqmQADwkYzTE1Pb4y2W+U3rE/iFkSWcWHG2LS6MJfj6SmHApg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.33.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" - } - }, - "@typescript-eslint/parser": { - "version": "2.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.33.0.tgz", - "integrity": "sha512-AUtmwUUhJoH6yrtxZMHbRUEMsC2G6z5NSxg9KsROOGqNXasM71I8P2NihtumlWTUCRld70vqIZ6Pm4E5PAziEA==", - "dev": true, - "requires": { - "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.33.0", - "@typescript-eslint/typescript-estree": "2.33.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "@typescript-eslint/typescript-estree": { - "version": "2.33.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.33.0.tgz", - "integrity": "sha512-d8rY6/yUxb0+mEwTShCQF2zYQdLlqihukNfG9IUlLYz5y1CH6G/9XYbrxQLq3Z14RNvkCC6oe+OcFlyUpwUbkg==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "eslint-visitor-keys": "^1.1.0", - "glob": "^7.1.6", - "is-glob": "^4.0.1", - "lodash": "^4.17.15", - "semver": "^7.3.2", - "tsutils": "^3.17.1" - } - }, - "abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "requires": { - "event-target-shim": "^5.0.0" - } - }, - "acorn": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz", - "integrity": "sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ==", - "dev": true - }, - "acorn-jsx": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz", - "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==", - "dev": true - }, - "adal-node": { - "version": "0.1.28", - "resolved": "https://registry.npmjs.org/adal-node/-/adal-node-0.1.28.tgz", - "integrity": "sha1-RoxLs+u9lrEnBmn0ucuk4AZepIU=", - "requires": { - "@types/node": "^8.0.47", - "async": ">=0.6.0", - "date-utils": "*", - "jws": "3.x.x", - "request": ">= 2.52.0", - "underscore": ">= 1.3.1", - "uuid": "^3.1.0", - "xmldom": ">= 0.1.x", - "xpath.js": "~1.1.0" - }, - "dependencies": { - "@types/node": { - "version": "8.10.60", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.60.tgz", - "integrity": "sha512-YjPbypHFuiOV0bTgeF07HpEEqhmHaZqYNSdCKeBJa+yFoQ/7BC+FpJcwmi34xUIIRVFktnUyP1dPU8U0612GOg==" - } - } - }, - "adm-zip": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", - "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" - }, - "ajv": { - "version": "6.12.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", - "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "requires": { - "type-fest": "^0.11.0" - }, - "dependencies": { - "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", - "is-string": "^1.0.5" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" - }, - "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", - "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "requires": { - "fill-range": "^7.0.1" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", - "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cross-env": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", - "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", - "requires": { - "cross-spawn": "^7.0.0" - } - }, - "cross-spawn": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", - "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "date-utils": { - "version": "1.2.21", - "resolved": "https://registry.npmjs.org/date-utils/-/date-utils-1.2.21.tgz", - "integrity": "sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q=" - }, - "dateformat": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delay": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", - "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==" - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "requires": { - "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" - } - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dotenv": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", - "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.17.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", - "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.0.0.tgz", - "integrity": "sha512-qY1cwdOxMONHJfGqw52UOpZDeqXy8xmD0u8CT6jIstil72jkhURC704W8CFyTPDPllz4z4lu0Ql1+07PG/XdIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0", - "eslint-visitor-keys": "^1.1.0", - "espree": "^7.0.0", - "esquery": "^1.2.0", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz", - "integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", - "dev": true, - "requires": { - "debug": "^2.6.9", - "pkg-dir": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.20.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz", - "integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==", - "dev": true, - "requires": { - "array-includes": "^3.0.3", - "array.prototype.flat": "^1.2.1", - "contains-path": "^0.1.0", - "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.2", - "eslint-module-utils": "^2.4.1", - "has": "^1.0.3", - "minimatch": "^3.0.4", - "object.values": "^1.1.0", - "read-pkg-up": "^2.0.0", - "resolve": "^1.12.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz", - "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz", - "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", - "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", - "dev": true - }, - "espree": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.0.0.tgz", - "integrity": "sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz", - "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "dev": true, - "requires": { - "estraverse": "^4.1.0" - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" - }, - "events": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", - "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" - }, - "execa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.1.tgz", - "integrity": "sha512-SCjM/zlBdOK8Q5TIjOn6iEHZaPHFsMoTxXQ2nvUvtPnuohz3H2dIozSg+etNR98dGoYUp2ENSKLL/XaMmbxVgw==", - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extract-zip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", - "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", - "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" - }, - "fast-glob": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", - "integrity": "sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A==", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastq": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", - "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", - "requires": { - "reusify": "^1.0.4" - } - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", - "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^1.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "get-stream": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", - "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.1" - } - }, - "globby": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", - "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==" - } - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "inquirer": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz", - "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^3.0.0", - "cli-cursor": "^3.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.15", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.5.3", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" - }, - "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", - "dev": true - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsonfile": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", - "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^1.0.0" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" - }, - "merge2": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", - "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" - }, - "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.0.5" - } - }, - "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" - }, - "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", - "requires": { - "mime-db": "1.44.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "requires": { - "path-key": "^3.0.0" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", - "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "dev": true, - "requires": { - "find-up": "^2.1.0" - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, - "run-parallel": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", - "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" - }, - "rxjs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz", - "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" - }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" - }, - "simple-git": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.4.0.tgz", - "integrity": "sha512-lqeAiq+P7A7oIGIUllU1Jg9U2SHOdxzhnFU4p4yJdvNoR4O3lYGJCfaC4cGx//J7jkrE+FPs5dJR0JVg1wVwfQ==", - "requires": { - "@kwsites/exec-p": "^0.4.0", - "debug": "^4.0.1" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimleft": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", - "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimstart": "^1.0.0" - } - }, - "string.prototype.trimright": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", - "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "string.prototype.trimend": "^1.0.0" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", - "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "ts-node": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.1.tgz", - "integrity": "sha512-bdNz1L4ekHiJul6SHtZWs1ujEKERJnHs4HxN7rjTyyVOFf3HaJ6sLqe6aPG62XTzAB/63pKRh5jTSWL0D7bsvw==", - "requires": { - "arg": "^4.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "source-map-support": "^0.5.17", - "yn": "3.1.1" - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" - }, - "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "typescript": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.2.tgz", - "integrity": "sha512-q2ktq4n/uLuNNShyayit+DTobV2ApPEo/6so68JaD5ojvc/6GClBipedB9zNWYxRSAlZXAe405Rlijzl6qDiSw==" - }, - "underscore": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", - "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==" - }, - "universalify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", - "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, - "v8-compile-cache": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", - "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xmldom": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.3.0.tgz", - "integrity": "sha512-z9s6k3wxE+aZHgXYxSTpGDo7BYOUfJsIRyoZiX6HTjwpwfS2wpQBQKa2fD+ShLyPkqDYo5ud7KitmLZ2Cd6r0g==" - }, - "xpath.js": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/xpath.js/-/xpath.js-1.1.0.tgz", - "integrity": "sha512-jg+qkfS4K8E7965sqaUl8mRngXiKb3WZGfONgE18pr03FUQiuSV6G+Ej4tS55B+rIQSFEIw3phdVAQ4pPqNWfQ==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" - } - } -} +{ + "name": "roslyn-branches", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "roslyn-branches", + "version": "0.0.0", + "dependencies": { + "@azure/arm-appservice": "13.0.3", + "@azure/arm-resources": "5.1.0", + "@azure/arm-subscriptions": "5.1.0", + "@azure/identity": "4.2.0", + "@azure/storage-blob": "12.23.0", + "adm-zip": "0.4.14", + "chalk": "4.0.0", + "date-fns": "2.29.3", + "dateformat": "3.0.3", + "delay": "4.3.0", + "dotenv": "8.2.0", + "execa": "4.0.1", + "extract-zip": "2.0.0", + "fs-extra": "9.0.0", + "get-stream": "5.1.0", + "globby": "11.0.0", + "node-fetch": "3.3.2", + "simple-git": "3.24.0", + "strip-json-comments": "3.1.1", + "tsx": "4.11.2", + "typescript": "5.4.5" + }, + "devDependencies": { + "@types/adm-zip": "0.4.33", + "@types/dateformat": "3.0.1", + "@types/fs-extra": "9.0.0", + "@types/node": "16.18.0", + "@types/yargs": "15.0.5", + "@typescript-eslint/eslint-plugin": "7.12.0", + "@typescript-eslint/parser": "7.12.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1" + } + }, + "node_modules/@azure/abort-controller": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.1.tgz", + "integrity": "sha512-wP2Jw6uPp8DEDy0n4KNidvwzDjyVV2xnycEIq7nPzj1rHyb/r+t3OPeNT1INZePP2wy5ZqlwyuyOMTi0ePyY1A==", + "dependencies": { + "tslib": "^1.9.3" + } + }, + "node_modules/@azure/arm-appservice": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@azure/arm-appservice/-/arm-appservice-13.0.3.tgz", + "integrity": "sha512-Vu011o3/bikQNwtjouwmUJud+Z6Brcjij2D0omPWClRGg8i5gBfOYSpDkFGkHbhGlaky4fgvfkxD0uHGq34uYA==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/arm-appservice/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@azure/arm-resources": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@azure/arm-resources/-/arm-resources-5.1.0.tgz", + "integrity": "sha512-aZOnHfo+bt36KVSYZNbJFJM+F8QWTwRVxDjtyZG1g7su0Ok0Dgg3gyLK1GUZn3jPkNuDKm1KwZ/+E6vhB2HqCQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/arm-resources/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@azure/arm-subscriptions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz", + "integrity": "sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/arm-subscriptions/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@azure/core-auth": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-http-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", + "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-paging": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.4.0.tgz", + "integrity": "sha512-tabFtZTg8D9XqZKEfNUOGh63SuYeOxmvH4GDcOJN+R1bZWZ1FZskctgY9Pmuwzhn+0Xvq9rmimK9hsvtLkeBsw==", + "dependencies": { + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@azure/core-paging/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.0.tgz", + "integrity": "sha512-CeuTvsXxCUmEuxH5g/aceuSl6w2EugvNHKAtKKVdiX915EjJJxAwfzNNWZreNnbxHZ2fi0zaM6wwS23x2JVqSQ==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-tracing": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-tracing/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", + "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/core-xml": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.2.tgz", + "integrity": "sha512-CW3MZhApe/S4iikbYKE7s83fjDBPIr2kpidX+hlGRwh7N4o1nIpQ/PfJTeioqhfqdMvRtheEl+ft64fyTaLNaA==", + "dependencies": { + "fast-xml-parser": "^4.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-xml/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@azure/identity": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.2.0.tgz", + "integrity": "sha512-ve3aYv79qXOJ8wRxQ5jO0eIz2DZ4o0TyME4m4vlGV5YyePddVZ+pFMzusAMODNAflYAAv1cBIhKnd4xytmXyig==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.4.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.6.6", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/identity/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@azure/identity/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@azure/identity/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@azure/logger": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.0.tgz", + "integrity": "sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA==", + "dependencies": { + "tslib": "^1.9.3" + } + }, + "node_modules/@azure/msal-browser": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.16.0.tgz", + "integrity": "sha512-WKobvIisBK7sFSOwHuchH9tUMekwhJRLgLE9tKhIq0wFYGRcVGK0KivP5vZrobVZEMNCZWto0fI1VcSVoa+cig==", + "dependencies": { + "@azure/msal-common": "14.11.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "14.11.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.11.0.tgz", + "integrity": "sha512-B6+IKLFs7Lsr06vjX8dPN61ENpTgiFrHf+CVo1UasHcmk5uEOq5D4thrbjsauKX+xtFryYsCDtznVDmWS4/sCg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.9.1.tgz", + "integrity": "sha512-I9Pc78mXwj/K8ydSgTfZ5A20vQ/xvfgnnhSCkienZ29b59zFy/hb2Vxmc6Gvg5pNkimSqkPnAtGoBMxYOLBm1A==", + "dependencies": { + "@azure/msal-common": "14.11.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@azure/msal-node/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@azure/storage-blob": { + "version": "12.23.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.23.0.tgz", + "integrity": "sha512-c1KJ5R5hqR/HtvmFtTn/Y1BNMq45NUBp0LZH7yF8WFMET+wmESgEr0FVTu/Z5NonmfUjbgJZG5Nh8xHc5RdWGQ==", + "dependencies": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-client": "^1.6.2", + "@azure/core-http-compat": "^2.0.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.10.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/core-xml": "^1.3.2", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/storage-blob/node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/adm-zip": { + "version": "0.4.33", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz", + "integrity": "sha512-WM0DCWFLjXtddl0fu0+iN2ZF+qz8RF9RddG5OSy/S90AQz01Fu8lHn/3oTIZDxvG8gVcnBLAHMHOdBLbV6m6Mw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "node_modules/@types/dateformat": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz", + "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-xCbDUSZArlmMjiJdczt8AFNH2MwcMb/pj/HKja1hx3u1qzOUINcJktQMGoGVlgFnzxnuCahxKFlcRBkSAcm33g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.0.tgz", + "integrity": "sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==", + "devOptional": true + }, + "node_modules/@types/yargs": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", + "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.12.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", + "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==", + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delay": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", + "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.1.tgz", + "integrity": "sha512-SCjM/zlBdOK8Q5TIjOn6iEHZaPHFsMoTxXQ2nvUvtPnuohz3H2dIozSg+etNR98dGoYUp2ENSKLL/XaMmbxVgw==", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/extract-zip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.12.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-xml-parser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", + "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", + "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dependencies": { + "universalify": "^1.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/simple-git": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.24.0.tgz", + "integrity": "sha512-QqAKee9Twv+3k8IFOFfPB2hnk6as6Y6ACUpwCtQvRYBAes23Wv3SZlHVobAzqcE8gfsisCvPw3HGW3HYM+VYYw==", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", + "engines": { + "node": ">=4", + "npm": ">=6" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "node_modules/tsx": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.11.2.tgz", + "integrity": "sha512-V5DL5v1BuItjsQ2FN9+4OjR7n5cr8hSgN+VGmm/fd2/0cgQdBIWHcQ3bFYm/5ZTmyxkTDBUIaRuW2divgfPe0A==", + "dependencies": { + "esbuild": "~0.20.2", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@azure/abort-controller": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.0.1.tgz", + "integrity": "sha512-wP2Jw6uPp8DEDy0n4KNidvwzDjyVV2xnycEIq7nPzj1rHyb/r+t3OPeNT1INZePP2wy5ZqlwyuyOMTi0ePyY1A==", + "requires": { + "tslib": "^1.9.3" + } + }, + "@azure/arm-appservice": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@azure/arm-appservice/-/arm-appservice-13.0.3.tgz", + "integrity": "sha512-Vu011o3/bikQNwtjouwmUJud+Z6Brcjij2D0omPWClRGg8i5gBfOYSpDkFGkHbhGlaky4fgvfkxD0uHGq34uYA==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } + }, + "@azure/arm-resources": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@azure/arm-resources/-/arm-resources-5.1.0.tgz", + "integrity": "sha512-aZOnHfo+bt36KVSYZNbJFJM+F8QWTwRVxDjtyZG1g7su0Ok0Dgg3gyLK1GUZn3jPkNuDKm1KwZ/+E6vhB2HqCQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } + }, + "@azure/arm-subscriptions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@azure/arm-subscriptions/-/arm-subscriptions-5.1.0.tgz", + "integrity": "sha512-6BeOF2eQWNLq22ch7xP9RxYnPjtGev54OUCGggKOWoOvmesK7jUZbIyLk8JeXDT21PEl7iyYnxw78gxJ7zBxQw==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.3.0", + "@azure/core-client": "^1.6.1", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.2.0", + "@azure/core-rest-pipeline": "^1.8.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } + }, + "@azure/core-auth": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.1.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-client": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-rest-pipeline": "^1.9.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-http-compat": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", + "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-client": "^1.3.0", + "@azure/core-rest-pipeline": "^1.3.0" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-paging": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.4.0.tgz", + "integrity": "sha512-tabFtZTg8D9XqZKEfNUOGh63SuYeOxmvH4GDcOJN+R1bZWZ1FZskctgY9Pmuwzhn+0Xvq9rmimK9hsvtLkeBsw==", + "requires": { + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } + }, + "@azure/core-rest-pipeline": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.16.0.tgz", + "integrity": "sha512-CeuTvsXxCUmEuxH5g/aceuSl6w2EugvNHKAtKKVdiX915EjJJxAwfzNNWZreNnbxHZ2fi0zaM6wwS23x2JVqSQ==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-tracing": "^1.0.1", + "@azure/core-util": "^1.9.0", + "@azure/logger": "^1.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-tracing": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "requires": { + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-util": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", + "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", + "requires": { + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "requires": { + "tslib": "^2.6.2" + } + }, + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/core-xml": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.2.tgz", + "integrity": "sha512-CW3MZhApe/S4iikbYKE7s83fjDBPIr2kpidX+hlGRwh7N4o1nIpQ/PfJTeioqhfqdMvRtheEl+ft64fyTaLNaA==", + "requires": { + "fast-xml-parser": "^4.3.2", + "tslib": "^2.6.2" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@azure/identity": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.2.0.tgz", + "integrity": "sha512-ve3aYv79qXOJ8wRxQ5jO0eIz2DZ4o0TyME4m4vlGV5YyePddVZ+pFMzusAMODNAflYAAv1cBIhKnd4xytmXyig==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.5.0", + "@azure/core-client": "^1.4.0", + "@azure/core-rest-pipeline": "^1.1.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.3.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^3.11.1", + "@azure/msal-node": "^2.6.6", + "events": "^3.0.0", + "jws": "^4.0.0", + "open": "^8.0.0", + "stoppable": "^1.1.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + } + } + }, + "@azure/logger": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.0.tgz", + "integrity": "sha512-g2qLDgvmhyIxR3JVS8N67CyIOeFRKQlX/llxYJQr1OSGQqM3HTpVP8MjmjcEKbL/OIt2N9C9UFaNQuKOw1laOA==", + "requires": { + "tslib": "^1.9.3" + } + }, + "@azure/msal-browser": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.16.0.tgz", + "integrity": "sha512-WKobvIisBK7sFSOwHuchH9tUMekwhJRLgLE9tKhIq0wFYGRcVGK0KivP5vZrobVZEMNCZWto0fI1VcSVoa+cig==", + "requires": { + "@azure/msal-common": "14.11.0" + } + }, + "@azure/msal-common": { + "version": "14.11.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.11.0.tgz", + "integrity": "sha512-B6+IKLFs7Lsr06vjX8dPN61ENpTgiFrHf+CVo1UasHcmk5uEOq5D4thrbjsauKX+xtFryYsCDtznVDmWS4/sCg==" + }, + "@azure/msal-node": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.9.1.tgz", + "integrity": "sha512-I9Pc78mXwj/K8ydSgTfZ5A20vQ/xvfgnnhSCkienZ29b59zFy/hb2Vxmc6Gvg5pNkimSqkPnAtGoBMxYOLBm1A==", + "requires": { + "@azure/msal-common": "14.11.0", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + } + } + }, + "@azure/storage-blob": { + "version": "12.23.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.23.0.tgz", + "integrity": "sha512-c1KJ5R5hqR/HtvmFtTn/Y1BNMq45NUBp0LZH7yF8WFMET+wmESgEr0FVTu/Z5NonmfUjbgJZG5Nh8xHc5RdWGQ==", + "requires": { + "@azure/abort-controller": "^1.0.0", + "@azure/core-auth": "^1.4.0", + "@azure/core-client": "^1.6.2", + "@azure/core-http-compat": "^2.0.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.1.1", + "@azure/core-rest-pipeline": "^1.10.1", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.6.1", + "@azure/core-xml": "^1.3.2", + "@azure/logger": "^1.0.0", + "events": "^3.0.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + } + } + }, + "@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@types/adm-zip": { + "version": "0.4.33", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.4.33.tgz", + "integrity": "sha512-WM0DCWFLjXtddl0fu0+iN2ZF+qz8RF9RddG5OSy/S90AQz01Fu8lHn/3oTIZDxvG8gVcnBLAHMHOdBLbV6m6Mw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "@types/dateformat": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-3.0.1.tgz", + "integrity": "sha512-KlPPdikagvL6ELjWsljbyDIPzNCeliYkqRpI+zea99vBBbCIA5JNshZAwQKTON139c87y9qvTFVgkFd14rtS4g==", + "dev": true + }, + "@types/fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-xCbDUSZArlmMjiJdczt8AFNH2MwcMb/pj/HKja1hx3u1qzOUINcJktQMGoGVlgFnzxnuCahxKFlcRBkSAcm33g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/node": { + "version": "16.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.0.tgz", + "integrity": "sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==", + "devOptional": true + }, + "@types/yargs": { + "version": "15.0.5", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", + "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", + "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "dev": true + }, + "@types/yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha512-A1b8SU4D10uoPjwb0lnHmmu8wZhR9d+9o2PKBQT2jU5YPTKsxac6M2qGAdY7VcL+dHHhARVUDmeg0rOrcd9EjA==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.12.0.tgz", + "integrity": "sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/type-utils": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + } + }, + "@typescript-eslint/parser": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.12.0.tgz", + "integrity": "sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.12.0.tgz", + "integrity": "sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.12.0.tgz", + "integrity": "sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "7.12.0", + "@typescript-eslint/utils": "7.12.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + } + }, + "@typescript-eslint/types": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.12.0.tgz", + "integrity": "sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.12.0.tgz", + "integrity": "sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/visitor-keys": "7.12.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@typescript-eslint/utils": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.12.0.tgz", + "integrity": "sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.12.0", + "@typescript-eslint/types": "7.12.0", + "@typescript-eslint/typescript-estree": "7.12.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.12.0.tgz", + "integrity": "sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.12.0", + "eslint-visitor-keys": "^3.4.3" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "adm-zip": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.14.tgz", + "integrity": "sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g==" + }, + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "requires": { + "debug": "^4.3.4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + } + }, + "array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==" + }, + "array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + } + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" + }, + "available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "requires": { + "possible-typed-array-names": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==" + }, + "data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + } + }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delay": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.3.0.tgz", + "integrity": "sha512-Lwaf3zVFDMBop1yDuFZ19F9WyGcZcGacsbdlZtWjQmM50tOcMntm1njF/Nb/Vjij3KaSvCF+sEYGKrrjObu2NA==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + } + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "es-abstract": { + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + } + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true + }, + "es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + } + }, + "es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "requires": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "requires": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==" + }, + "execa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.1.tgz", + "integrity": "sha512-SCjM/zlBdOK8Q5TIjOn6iEHZaPHFsMoTxXQ2nvUvtPnuohz3H2dIozSg+etNR98dGoYUp2ENSKLL/XaMmbxVgw==", + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "extract-zip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.0.tgz", + "integrity": "sha512-i42GQ498yibjdvIhivUsRslx608whtGoFIhF26Z7O4MYncBxp8CwalOs1lnHy21A9sIohWO2+uiE4SRtC9JXDg==", + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-xml-parser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz", + "integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==", + "requires": { + "strnum": "^1.0.5" + } + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "fs-extra": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz", + "integrity": "sha512-pmEYSk3vYsG/bF651KPUXZ+hvjpgWYw/Gc7W9NFUe3ZVLczKKWIij3IKpOrQcdw4TILtibFslZ0UmR8Vvzig4g==", + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + } + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + } + }, + "get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "requires": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + } + }, + "globby": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.0.tgz", + "integrity": "sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==", + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.3" + } + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" + }, + "ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==" + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + } + }, + "is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + } + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "requires": { + "is-typed-array": "^1.1.13" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "requires": { + "which-typed-array": "^1.1.14" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==" + }, + "node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + } + }, + "object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + } + }, + "object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + } + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "requires": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + } + }, + "semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==" + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-git": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.24.0.tgz", + "integrity": "sha512-QqAKee9Twv+3k8IFOFfPB2hnk6as6Y6ACUpwCtQvRYBAes23Wv3SZlHVobAzqcE8gfsisCvPw3HGW3HYM+VYYw==", + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" + }, + "stoppable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", + "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==" + }, + "string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" + }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "requires": {} + }, + "tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "tsx": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.11.2.tgz", + "integrity": "sha512-V5DL5v1BuItjsQ2FN9+4OjR7n5cr8hSgN+VGmm/fd2/0cgQdBIWHcQ3bFYm/5ZTmyxkTDBUIaRuW2divgfPe0A==", + "requires": { + "esbuild": "~0.20.2", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.5" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + } + }, + "typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "requires": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + } + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==" + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + } + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/#scripts/roslyn-branches/package.json b/#scripts/roslyn-branches/package.json index d577d9b31..5e19e980c 100644 --- a/#scripts/roslyn-branches/package.json +++ b/#scripts/roslyn-branches/package.json @@ -4,28 +4,31 @@ "description": "Build process for Roslyn branches", "private": true, "scripts": { - "generate-run-matrix": "ts-node-script ./generateGitHubRunMatrix.ts", - "build-branch": "ts-node-script ./buildBranch.ts" + "generate-matrix": "tsx ./flow/prepare/prepareBranchMatrices.ts", + "update-branch": "tsx ./flow/update/updateBranch.ts", + "cleanup-branch": "tsx ./flow/cleanup/cleanupBranch.ts", + "check": "tsc --project tsconfig.json --noEmit --skipLibCheck && eslint . --max-warnings 0 --ext .ts" }, "devDependencies": { "@types/adm-zip": "0.4.33", "@types/dateformat": "3.0.1", "@types/fs-extra": "9.0.0", - "@types/node": "14.0.1", + "@types/node": "16.18.0", "@types/yargs": "15.0.5", - "@typescript-eslint/eslint-plugin": "2.33.0", - "@typescript-eslint/parser": "2.33.0", - "eslint": "7.0.0", - "eslint-plugin-import": "2.20.2" + "@typescript-eslint/eslint-plugin": "7.12.0", + "@typescript-eslint/parser": "7.12.0", + "eslint": "8.56.0", + "eslint-plugin-import": "2.29.1" }, "dependencies": { - "@azure/arm-appservice": "6.0.0", - "@azure/arm-authorization": "8.3.3", - "@azure/arm-resources": "2.1.0", - "@azure/ms-rest-nodeauth": "3.0.3", - "@azure/storage-blob": "12.1.1", + "@azure/arm-appservice": "13.0.3", + "@azure/arm-resources": "5.1.0", + "@azure/arm-subscriptions": "5.1.0", + "@azure/identity": "4.2.0", + "@azure/storage-blob": "12.23.0", "adm-zip": "0.4.14", "chalk": "4.0.0", + "date-fns": "2.29.3", "dateformat": "3.0.3", "delay": "4.3.0", "dotenv": "8.2.0", @@ -34,9 +37,10 @@ "fs-extra": "9.0.0", "get-stream": "5.1.0", "globby": "11.0.0", - "simple-git": "2.4.0", + "node-fetch": "3.3.2", + "simple-git": "3.24.0", "strip-json-comments": "3.1.1", - "ts-node": "8.10.1", - "typescript": "3.9.2" + "tsx": "4.11.2", + "typescript": "5.4.5" } } diff --git a/#scripts/roslyn-branches/shared/azureResourceGroupName.ts b/#scripts/roslyn-branches/shared/azureResourceGroupName.ts new file mode 100644 index 000000000..33c271736 --- /dev/null +++ b/#scripts/roslyn-branches/shared/azureResourceGroupName.ts @@ -0,0 +1 @@ +export const AZURE_RESOURCE_GROUP_NAME = 'SharpLab'; \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/branchesJson.ts b/#scripts/roslyn-branches/shared/branchesJson.ts new file mode 100644 index 000000000..9f00caa44 --- /dev/null +++ b/#scripts/roslyn-branches/shared/branchesJson.ts @@ -0,0 +1,76 @@ +import path from 'path'; +import fs from 'fs-extra'; +import getStream from 'get-stream'; +import { type BlobDownloadResponseParsed, BlobServiceClient } from '@azure/storage-blob'; +import { getAzureCredential } from './getAzureCredential'; +import { useAzure } from './useAzure'; +import type { Branch } from './types'; +import { buildRootPath } from './paths'; + +const branchesJsonFileName = 'branches.json'; + +const getBranchesJsonBlobClient = () => { + const blobServiceUrl = 'https://slbs.blob.core.windows.net'; + const credential = getAzureCredential(); + const blobServiceClient = new BlobServiceClient(blobServiceUrl, credential); + return blobServiceClient.getContainerClient('public') + .getBlockBlobClient(branchesJsonFileName); +}; + +const parseBranchesFromDownload = async (download: BlobDownloadResponseParsed) => { + return JSON.parse( + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await getStream(download.readableStreamBody!) + ) as Array; +}; + +export const getBranchesJson = async (): Promise> => { + const blobClient = getBranchesJsonBlobClient(); + const download = await blobClient.download(); + + return parseBranchesFromDownload(download); +}; + +async function updateInAzureBlob(branch: Branch, branchesJsonArtifactPath: string) { + const blobClient = getBranchesJsonBlobClient(); + + console.log(`Downloading current ${branchesJsonFileName} from Azure...`); + const download = await blobClient.download(); + console.log(` ETag: ${download.etag ?? ''}`); + const branches = await parseBranchesFromDownload(download); + + const branchIndex = branches + .map((branch, index) => ({ branch, index })) + .find(x => x.branch.id === branch.id) + ?.index; + if (branchIndex) { + branches.splice(branchIndex, 1, branch); + } + else { + branches.push(branch); + } + + const branchesJson = JSON.stringify(branches, null, 2); + await fs.writeFile(branchesJsonArtifactPath, branchesJson); + + console.log(`Uploading updated ${branchesJsonFileName} to Azure...`); + await blobClient.upload(branchesJson, Buffer.byteLength(branchesJson), { + blobHTTPHeaders: { + blobContentType: 'application/json', + blobCacheControl: 'max-age=43200' // 12 hours + }, + conditions: { ifMatch: download.etag } + }); + console.log(' Done.'); +} + +export async function updateInBranchesJson(branch: Branch) { + const branchesJsonArtifactPath = path.join(buildRootPath, branchesJsonFileName); + if (useAzure) { + await updateInAzureBlob(branch, branchesJsonArtifactPath); + } + else { + // TODO: migrate to TypeScript + throw new Error('Not migrated to TypeScript yet.'); + } +} \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/getAzureCredential.ts b/#scripts/roslyn-branches/shared/getAzureCredential.ts new file mode 100644 index 000000000..02d516d6c --- /dev/null +++ b/#scripts/roslyn-branches/shared/getAzureCredential.ts @@ -0,0 +1,43 @@ +import { SubscriptionClient } from '@azure/arm-subscriptions'; +import { ClientSecretCredential, type TokenCredential } from '@azure/identity'; + +let cachedCredential: TokenCredential | undefined; +let cachedSubscriptionId: string | undefined; + +function getEnvForAzure(name: string) { + const value = process.env[name]; + if (!value) + throw `Environment variable ${name} is required for Azure deployment.`; + return value; +} + +export const getAzureCredential = () => { + if (!cachedCredential) { + console.log('Configuring Azure credential...'); + const appId = getEnvForAzure('SL_BUILD_AZURE_APP_ID'); + const secret = getEnvForAzure('SL_BUILD_AZURE_SECRET'); + const tenantId = getEnvForAzure('SL_BUILD_AZURE_TENANT'); + + cachedCredential = new ClientSecretCredential(tenantId, appId, secret); + } + return cachedCredential; +}; + +export const getAzureCredentialWithSubscriptionId = async () => { + const credential = getAzureCredential(); + if (!cachedSubscriptionId) { + console.log('Getting Azure subscriptions...'); + const subscriptions = new SubscriptionClient(credential).subscriptions.list(); + let subscriptionId: string | undefined; + for await (const subscription of subscriptions) { + if (subscriptionId) + throw new Error(`Expected single Azure subscription, but got multiple.`); + ({ subscriptionId } = subscription); + } + if (!subscriptionId) + throw new Error(`Expected single Azure subscription, but got none.`); + cachedSubscriptionId = subscriptionId; + } + + return { credential, subscriptionId: cachedSubscriptionId }; +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/nodeSafeTopLevelAwait.ts b/#scripts/roslyn-branches/shared/nodeSafeTopLevelAwait.ts new file mode 100644 index 000000000..4ef93e5ae --- /dev/null +++ b/#scripts/roslyn-branches/shared/nodeSafeTopLevelAwait.ts @@ -0,0 +1,25 @@ +export const nodeSafeTopLevelAwait = ( + call: () => Promise, + handleError: (e: unknown) => void, + { timeoutMinutes }: { timeoutMinutes: number } +) => { + let keepaliveTimer: ReturnType; + // https://github.com/nodejs/node/issues/22088 + const keepalive = () => new Promise((_, reject) => keepaliveTimer = setTimeout( + () => reject(new Error(`Top-level async timed out within ${timeoutMinutes} minutes.`)), timeoutMinutes * 60 * 1000 + )); + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + (async () => { + try { + await Promise.race([call(), keepalive()]); + } + catch (e) { + handleError(e); + } + finally { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + clearTimeout(keepaliveTimer!); + } + })(); +}; \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/paths.ts b/#scripts/roslyn-branches/shared/paths.ts new file mode 100644 index 000000000..53c68e775 --- /dev/null +++ b/#scripts/roslyn-branches/shared/paths.ts @@ -0,0 +1,6 @@ +import path from 'path'; +import fs from 'fs-extra'; + +export const rootPath = path.resolve(path.join(__dirname, '..', '..', '..')); +export const buildRootPath = path.join(rootPath, '!roslyn-branches'); +fs.ensureDirSync(buildRootPath); \ No newline at end of file diff --git a/#scripts/roslyn-branches/helpers/safeFetch.ts b/#scripts/roslyn-branches/shared/safeFetch.ts similarity index 71% rename from #scripts/roslyn-branches/helpers/safeFetch.ts rename to #scripts/roslyn-branches/shared/safeFetch.ts index 7192857e2..71720457c 100644 --- a/#scripts/roslyn-branches/helpers/safeFetch.ts +++ b/#scripts/roslyn-branches/shared/safeFetch.ts @@ -1,9 +1,9 @@ -import fetch, { RequestInit, Response } from 'node-fetch'; +import fetch, { type RequestInit, Response } from 'node-fetch'; export { Response }; export type SafeFetchError = Error & { response: Response }; -export default async function safeFetch(url: string, init?: RequestInit) { +export async function safeFetch(url: string, init?: RequestInit) { const response = await fetch(url, init); if (response.status >= 400) { const error = new Error(`${response.status} ${response.statusText}:\n${await response.text()}`); diff --git a/#scripts/roslyn-branches/shared/safeGetArgument.ts b/#scripts/roslyn-branches/shared/safeGetArgument.ts new file mode 100644 index 000000000..2f60b91af --- /dev/null +++ b/#scripts/roslyn-branches/shared/safeGetArgument.ts @@ -0,0 +1,3 @@ +export const safeGetArgument = (index: number, name: string) => + // "2 +" is for the ts-node-script + (process.argv[2 + index] ?? (() => { throw new Error(`${name} was not provided`); })()) as T; \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/types.ts b/#scripts/roslyn-branches/shared/types.ts new file mode 100644 index 000000000..2ed26798c --- /dev/null +++ b/#scripts/roslyn-branches/shared/types.ts @@ -0,0 +1,56 @@ +type BaseBranch = { + readonly id: string; + readonly name: string; + readonly group: string; + readonly url: string; + readonly sharplab?: { + readonly supportsUnknownOptions: boolean; + }; +}; + +type PlatformBranch = BaseBranch & { + readonly kind: 'platform'; +}; + +type BaseRoslynBranch = BaseBranch & { + readonly kind: 'roslyn'; + readonly feature?: { + readonly language: string; + readonly name: string; + readonly url: string; + }; + readonly commits: ReadonlyArray; +}; + +export type ActiveRoslynBranch = BaseRoslynBranch & { + readonly merged?: undefined; +}; + +export type MergedRoslynBranch = BaseRoslynBranch & { + readonly merged: true; + readonly mergeDetected: string; + readonly sharplab?: { + readonly stopped?: undefined; + } | { + readonly stopped: string; + readonly deleted?: string; + } +}; + +export type RoslynBranch = ActiveRoslynBranch | MergedRoslynBranch; +export type Branch = PlatformBranch | RoslynBranch; + +export type Commit = { + readonly date: string; + readonly message: string; + readonly author: string; + readonly hash: string; +}; + +export type CleanupAction = + | 'fail-not-merged' + | 'mark-as-merged' + | 'wait' + | 'stop' + | 'delete' + | 'done'; \ No newline at end of file diff --git a/#scripts/roslyn-branches/shared/useAzure.ts b/#scripts/roslyn-branches/shared/useAzure.ts new file mode 100644 index 000000000..8257a9273 --- /dev/null +++ b/#scripts/roslyn-branches/shared/useAzure.ts @@ -0,0 +1 @@ +export const useAzure = process.env.SL_DEPLOY_MODE === 'Azure'; \ No newline at end of file diff --git a/#scripts/roslyn-branches/steps/getAzureCredentials.ts b/#scripts/roslyn-branches/steps/getAzureCredentials.ts deleted file mode 100644 index 98868ad9e..000000000 --- a/#scripts/roslyn-branches/steps/getAzureCredentials.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as msRestNodeAuth from '@azure/ms-rest-nodeauth'; - -const noAudience = Symbol('no-audience') as unknown as 'symbol:no-audience'; - -function getEnvForAzure(name: string) { - const value = process.env[name]; - if (!value) - throw `Environment variable ${name} is required for Azure deployment.`; - return value; -} - -async function loginToAzure(tokenAudience?: string) { - const appId = getEnvForAzure('SL_BUILD_AZURE_APP_ID'); - const secret = getEnvForAzure('SL_BUILD_AZURE_SECRET'); - const tenantId = getEnvForAzure('SL_BUILD_AZURE_TENANT'); - - console.log('Logging in to Azure...'); - const { credentials, subscriptions } = await msRestNodeAuth.loginWithServicePrincipalSecretWithAuthResponse(appId, secret, tenantId, { - ...(tokenAudience ? { tokenAudience } : {}) - }); - if (tokenAudience) - return { credentials }; - - if (!subscriptions || subscriptions.length !== 1) - throw new Error(`Expected single Azure subscription, but got ${subscriptions?.length ?? ''}.`); - - return { credentials, subscriptionId: subscriptions[0].id }; -} - -type UnwrapPromise = T extends PromiseLike ? U : T; -const cached = {} as Record>|undefined>; - -async function getAzureCredentialsInternal(audience?: string) { - let result = cached[audience ?? noAudience]; - if (!result) { - result = await loginToAzure(audience); - cached[audience ?? noAudience] = result; - } - - return result; -} - -export const getAzureCredentials = () => getAzureCredentialsInternal() as Promise<{ - credentials: msRestNodeAuth.TokenCredentialsBase; - subscriptionId: string; -}>; -export const getAzureCredentialsForAudience = async (audience: string) => (await getAzureCredentialsInternal(audience)).credentials; \ No newline at end of file diff --git a/#scripts/roslyn-branches/steps/publishBranch.ts b/#scripts/roslyn-branches/steps/publishBranch.ts deleted file mode 100644 index dc4451542..000000000 --- a/#scripts/roslyn-branches/steps/publishBranch.ts +++ /dev/null @@ -1,167 +0,0 @@ -import path from 'path'; -import fs from 'fs-extra'; -import stripJsonComments from 'strip-json-comments'; -import delay from 'delay'; -import { ResourceManagementClient } from '@azure/arm-resources'; -import { WebSiteManagementClient } from '@azure/arm-appservice'; -import AdmZip from 'adm-zip'; -import dateFormat from 'dateformat'; -import safeFetch, { Response, SafeFetchError } from '../helpers/safeFetch'; -import useAzure from '../helpers/useAzure'; -import { getAzureCredentials } from './getAzureCredentials'; - -const resourceGroupName = 'SharpLab'; - -export default async function publishBranch({ webAppName, webAppUrl, branchArtifactsRoot, branchSiteRoot }: { - webAppName: string; - iisSiteName: string; - webAppUrl: string; - branchArtifactsRoot: string; - branchSiteRoot: string; -}) { - async function testBranchWebApp() { - console.log(`GET ${webAppUrl}/status`); - let ok = false; - let tryPermanent = 1; - let tryTemporary = 1; - - const formatStatus = ({ status, statusText }: Pick) => - ` ${status} ${statusText}`; - - while (tryPermanent < 3 && tryTemporary < 30) { - try { - const response = await safeFetch(`${webAppUrl}/status`); - ok = true; - console.log(formatStatus(response)); - break; - } - catch (e) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - if (e.response) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - console.warn(formatStatus(e.response)); - } - - const temporary = (e as Partial).response?.status === 503; - if (temporary) { - tryTemporary += 1; - } - else { - tryPermanent += 1; - } - console.warn(e); - } - await delay(1000); - } - - if (!ok) - throw new Error(`Failed to get success from ${webAppUrl}/status`); - } - - async function publishToAzure() { - const armTemplate = JSON.parse(stripJsonComments( - await fs.readFile(path.join(__dirname, '../arm/template.json'), 'utf-8') - )); - const armParameters = (JSON.parse(await fs.readFile(path.join(__dirname, '../arm/parameters.json'), 'utf-8')) as { - parameters: Record; - }).parameters; - - console.log(`Deploying to Azure, ${webAppName}...`); - - const { credentials, subscriptionId } = await getAzureCredentials(); - - const azureResourceClient = new ResourceManagementClient(credentials, subscriptionId); - const azureWebAppClient = new WebSiteManagementClient(credentials, subscriptionId); - - console.log(` Deploying web app...`); - const result = await azureResourceClient.deployments.createOrUpdate( - resourceGroupName, - webAppName.replace(/^sl-b-/, 'sharplab-branch-'), - { - properties: { - mode: 'Incremental', - template: armTemplate, - parameters: { - // eslint-disable-next-line @typescript-eslint/camelcase - sites_name: { value: webAppName }, - ...armParameters - } - } - } - ); - console.log(` Response: ${result._response.status}`); - console.log(` Provisioning: ${result.properties?.provisioningState ?? ''}`); - - console.log(` Zipping...`); - const zipPath = path.join(branchArtifactsRoot, 'Site.zip'); - console.log(` => ${zipPath}`); - const zip = new AdmZip(); - zip.addLocalFolder(branchSiteRoot); - zip.writeZip(zipPath); - - console.log(` Publishing...`); - const { - publishingUserName, - publishingPassword - } = await azureWebAppClient.webApps.listPublishingCredentials(resourceGroupName, webAppName); - const authHeader = { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - 'Authorization': `Basic ${Buffer.from(`${publishingUserName}:${publishingPassword!}`).toString('base64')}` - } as const; - - console.log(` ⏱️ ${dateFormat(new Date(), 'HH:MM:ss')}`); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const deploymentUrl = (await safeFetch(`https://${webAppName}.scm.azurewebsites.net/api/zipdeploy?isAsync=true`, { - method: 'POST', - body: fs.createReadStream(zipPath), - headers: { - ...authHeader, - 'Content-Length': (await fs.stat(zipPath)).size.toString() - }, - redirect: 'manual' - })).headers.get('Location')!; - - let deployment: { - id: string; - complete: boolean; - provisioningState: 'Succeeded'|'Failed'; - log_url: string; - }; - process.stdout.write(' '); - try { - do { - process.stdout.write('░'); - await delay(500); - deployment = await (await safeFetch(deploymentUrl, { - headers: { - ...authHeader - } - })).json() as typeof deployment; - } while (!deployment.complete); - - // https://github.com/projectkudu/kudu/issues/2906 - const logUrl = deployment.log_url.replace('/latest/', `/${deployment.id}/`); - if (deployment.provisioningState !== 'Succeeded') - throw new Error(`Deployment state: ${deployment.provisioningState}, logs at ${logUrl}`); - } - catch (e) { - console.log(''); - throw e; - } - - console.log(''); - console.log(` ✔️ ${dateFormat(new Date(), 'HH:MM:ss')}`); - - console.log(` Done.`); - } - - if (useAzure) { - await publishToAzure(); - } - else { - // TODO: migrate to TypeScript - throw new Error('Not migrated to TypeScript yet.'); - } - - await testBranchWebApp(); -} \ No newline at end of file diff --git a/#scripts/roslyn-branches/steps/updateInBranchesJson.ts b/#scripts/roslyn-branches/steps/updateInBranchesJson.ts deleted file mode 100644 index 11d752cd1..000000000 --- a/#scripts/roslyn-branches/steps/updateInBranchesJson.ts +++ /dev/null @@ -1,149 +0,0 @@ -import path from 'path'; -import fs from 'fs-extra'; -import getStream from 'get-stream'; -import { BlobServiceClient } from '@azure/storage-blob'; -import useAzure from '../helpers/useAzure'; -import safeFetch from '../helpers/safeFetch'; -import { getAzureCredentialsForAudience } from './getAzureCredentials'; - -const languageFeatureMapUrl = 'https://raw.githubusercontent.com/dotnet/roslyn/main/docs/Language%20Feature%20Status.md'; -const branchesJsonFileName = 'branches.json'; - -async function getRoslynBranchFeatureMap(buildRoot: string) { - const markdown = await (await safeFetch(languageFeatureMapUrl)).text(); - const languageVersions = markdown.matchAll(/#\s*(?.+)\s*$\s*(?
(?:^\|.+$\s*)+)/gm); - - const mapPath = `${buildRoot}/RoslynFeatureMap.json`; - let map = {} as Record; - if (await fs.pathExists(mapPath)) - map = await fs.readJson(mapPath); - - for (const languageMatch of languageVersions) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { language, table } = languageMatch.groups!; - const rows = table.matchAll(/^\|(?[^|]+)\|.+roslyn\/tree\/(?[A-Za-z\d\-/]+)/gm); - - for (const rowMatch of rows) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { rawName, branch } = rowMatch.groups!; - let name = rawName.trim(); - let url = ''; - const link = name.match(/\[([^\]]+)\]\(([^)]+)\)/); - if (link) - ([, name, url] = link); - - map[branch] = { language, name, url }; - } - } - - await fs.writeFile(mapPath, JSON.stringify(map, null, 2)); - return map; -} - -async function updateInAzureBlob(branch: { - id: string; - name: string; - group: string; - kind: string; - url: string; - feature?: { - language: string; - name: string; - url: string; - }; - commits: Array<{ - date: string; - message: string; - author: string; - hash: string; - }>; -}, branchesJsonArtifactPath: string) { - const blobServiceUrl = 'https://slbs.blob.core.windows.net'; - const credentials = await getAzureCredentialsForAudience(blobServiceUrl); - const blobServiceClient = new BlobServiceClient( - blobServiceUrl, - { - async getToken() { - const response = await credentials.getToken(); - return { - token: response.accessToken, - expiresOnTimestamp: (response.expiresOn as Date).getTime() / 1000 - }; - } - } - ); - const blobClient = blobServiceClient.getContainerClient('public').getBlockBlobClient('branches.json'); - - console.log(`Downloading current ${branchesJsonFileName} from Azure...`); - const download = await blobClient.download(); - console.log(` ETag: ${download.etag ?? ''}`); - const branches = JSON.parse( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await getStream(download.readableStreamBody!) - ) as Array; - - const branchIndex = branches - .map((branch, index) => ({ branch, index })) - .find(x => x.branch.id === branch.id) - ?.index; - if (branchIndex) { - branches.splice(branchIndex, 1, branch); - } - else { - branches.push(branch); - } - - const branchesJson = JSON.stringify(branches, null, 2); - await fs.writeFile(branchesJsonArtifactPath, branchesJson); - - console.log(`Uploading updated ${branchesJsonFileName} to Azure...`); - await blobClient.upload(branchesJson, branchesJson.length, { - blobHTTPHeaders: { - blobContentType: 'application/json', - blobCacheControl: 'max-age=43200' // 12 hours - }, - conditions: { ifMatch: download.etag } - }); - console.log(' Done.'); -} - -export default async function updateInBranchesJson( - { branch, buildRoot }: { - branch: { - name: string; - id: string; - url: string; - commits: Array<{ - date: string; - message: string; - author: string; - hash: string; - }>; - }; - buildRoot: string; - } -) { - const roslynBranchFeatureMap = await getRoslynBranchFeatureMap(buildRoot); - const feature = roslynBranchFeatureMap[branch.name]; - const branchJson = { - id: branch.id, - name: branch.name, - group: 'Roslyn branches', - kind: 'roslyn', - url: branch.url, - ...(feature ? { feature } : {}), - commits: branch.commits, - sharplab: { - supportsUnknownOptions: true - } - }; - - const branchesJsonArtifactPath = path.join(buildRoot, branchesJsonFileName); - if (useAzure) { - await updateInAzureBlob(branchJson, branchesJsonArtifactPath); - } - else { - // TODO: migrate to TypeScript - throw new Error('Not migrated to TypeScript yet.'); - } -} \ No newline at end of file diff --git a/#scripts/roslyn-branches/tsconfig.json b/#scripts/roslyn-branches/tsconfig.json index d3d8338ea..4f6c38429 100644 --- a/#scripts/roslyn-branches/tsconfig.json +++ b/#scripts/roslyn-branches/tsconfig.json @@ -8,7 +8,7 @@ "moduleResolution": "node", "noEmit": true, "strict": true, - "importsNotUsedAsValues": "error", + "verbatimModuleSyntax": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true } diff --git a/#scripts/run.ps1 b/#scripts/run.ps1 index 2d7d6ba67..10ae01bc5 100644 --- a/#scripts/run.ps1 +++ b/#scripts/run.ps1 @@ -1,13 +1,16 @@ param ( - [switch] [boolean] $ServerOnly = $false + [switch] [boolean] $ServerOnly = $false, + [switch] [boolean] $NoCache = $false ) Set-StrictMode -Version 2 $ErrorActionPreference = 'Stop' Write-Host "Opening new window for initial wait" -ForegroundColor White -Start-Process powershell -ArgumentList "-File `"$PSScriptRoot/run/wait.ps1`"" +Start-Process pwsh -ArgumentList "-File `"$PSScriptRoot/run/wait.ps1`"" -$tags = $ServerOnly ? @('server-only') : @(); +$tags = @('--tags', 'server') +if (!$ServerOnly) { $tags += @('--tags', 'assets') } +if (!$NoCache) { $tags += @('--tags', 'cache') } -dotnet tye run --watch --tags $tags \ No newline at end of file +dotnet tye run --watch @tags \ No newline at end of file diff --git a/#scripts/setup.ps1 b/#scripts/setup.ps1 index bd410e2da..03ebe8012 100644 --- a/#scripts/setup.ps1 +++ b/#scripts/setup.ps1 @@ -7,11 +7,15 @@ if ($LastExitCode -ne 0) { throw "git failed with exit code $LastExitCode" } -Write-Host "Creating stub .env" -ForegroundColor White +Write-Host "Creating stub .envs" -ForegroundColor White if (!(Test-Path './source/WebApp.Server/.env')) { Copy-Item './source/WebApp.Server/.env.template' './source/WebApp.Server/.env' } +if (!(Test-Path './source/Container.Manager/.env')) { + Copy-Item './source/Container.Manager/.env.template' './source/Container.Manager/.env' +} + Write-Host "Installing local tools" -ForegroundColor White dotnet tool restore if ($LastExitCode -ne 0) { @@ -23,6 +27,10 @@ npm install azurite -g if ($LastExitCode -ne 0) { throw "npm install failed with exit code $LastExitCode" } +$azuriteTempPath = './!azurite' +if (-not (Test-Path $azuriteTempPath)) { + New-Item $azuriteTempPath -Type Directory | Out-Null +} Write-Host "Preparing externals: mirrorsharp" -ForegroundColor White Push-Location './source/#external/mirrorsharp/WebAssets' @@ -33,9 +41,26 @@ try { } npm run build + if ($LastExitCode -ne 0) { + throw "npm run build failed with exit code $LastExitCode" + } +} +finally { + Pop-Location +} + +Write-Host "Preparing externals: mirrorsharp-codemirror-6-preview" -ForegroundColor White +Push-Location './source/#external/mirrorsharp-codemirror-6-preview/WebAssets' +try { + npm ci if ($LastExitCode -ne 0) { throw "npm ci failed with exit code $LastExitCode" } + + npm run build + if ($LastExitCode -ne 0) { + throw "npm run build failed with exit code $LastExitCode" + } } finally { Pop-Location @@ -44,7 +69,7 @@ finally { Write-Host "Installing node modules" -ForegroundColor White Push-Location './source/WebApp' try { - npm ci + npm ci if ($LastExitCode -ne 0) { throw "npm ci failed with exit code $LastExitCode" } @@ -53,8 +78,36 @@ finally { Pop-Location } +Write-Host "Preparing container host" -ForegroundColor White +Push-Location './source/Container.Manager' +try { + dotnet build + if ($LastExitCode -ne 0) { + throw "dotnet build failed with exit code $LastExitCode" + } + + $containerCapabilityId = New-Object Security.Principal.SecurityIdentifier @( + 'S-1-15-3-1024-4233803318-1181731508-1220533431-3050556506-2713139869-1168708946-594703785-1824610955' + ) + $aclRule = New-Object Security.AccessControl.FileSystemAccessRule @( + $containerCapabilityId, + [Security.AccessControl.FileSystemRights]::ReadAndExecute, + ([Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [Security.AccessControl.InheritanceFlags]::ObjectInherit), + [Security.AccessControl.PropagationFlags]::None, + [Security.AccessControl.AccessControlType]::Allow + ) + + $binPath = './bin/Debug/net9.0' + $acl = Get-Acl $binPath + $acl.AddAccessRule($aclRule); + Set-Acl $binPath -AclObject $acl +} +finally { + Pop-Location +} + Write-Host "" Write-Host "SharpLab setup done." -ForegroundColor White Write-Host "Run " -ForegroundColor White -NoNewLine Write-Host "sl run" -ForegroundColor Cyan -NoNewLine -Write-Host " to start." -ForegroundColor White -NoNewLine \ No newline at end of file +Write-Host " to start." -ForegroundColor White -NoNewLine diff --git a/.editorconfig b/.editorconfig index 24c050dcf..52d718b36 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,6 +19,7 @@ csharp_new_line_before_open_brace = none csharp_style_var_for_built_in_types = true:warning csharp_style_var_when_type_is_apparent = true:warning csharp_style_var_elsewhere = true:warning +csharp_style_namespace_declarations=file_scoped:warning dotnet_style_readonly_field = true:warning @@ -29,4 +30,17 @@ dotnet_diagnostic.CA1822.severity = none dotnet_diagnostic.IDE0005.severity = warning # IDE0090: 'new' expression can be simplified. -dotnet_diagnostic.IDE0090.severity = warning \ No newline at end of file +dotnet_diagnostic.IDE0090.severity = warning + +# IDE0300: Use collection expression for array +# IDE0301: Use collection expression for empty +# IDE0302: Use collection expression for stackalloc +# IDE0303: Use collection expression for Create() +# IDE0304: Use collection expression for builder +# IDE0305: Use collection expression for fluent +dotnet_diagnostic.IDE0300.severity = warning +dotnet_diagnostic.IDE0301.severity = warning +dotnet_diagnostic.IDE0302.severity = warning +dotnet_diagnostic.IDE0303.severity = warning +dotnet_diagnostic.IDE0304.severity = warning +dotnet_diagnostic.IDE0305.severity = warning \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/.eslintrc.json b/.github/actions/create-issues-from-app-insights/.eslintrc.json new file mode 100644 index 000000000..21a32f2bc --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/.eslintrc.json @@ -0,0 +1,74 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "ignorePatterns": ["index.js"], + "parserOptions": { + "ecmaVersion": 8, + "sourceType": "module", + "project": "tsconfig.json" + }, + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "env": { + "node": true + }, + "rules": { + "comma-dangle": "error", + "radix": "error", + "no-undefined": "error", + "no-duplicate-imports": "error", + "strict": "error", + "eqeqeq": ["error", "always", { "null": "ignore" }], + "no-plusplus": ["error", { "allowForLoopAfterthoughts": true }], + "no-sync": "error", + "no-new": "warn", + "linebreak-style": ["warn", "windows"], + "eol-last": ["warn", "never"], + "object-curly-spacing": ["warn", "always"], + "arrow-parens": ["warn", "as-needed"], + "dot-location": ["warn", "property"], + "operator-linebreak": ["warn", "before"], + "func-style": ["warn", "declaration", { "allowArrowFunctions": true }], + "prefer-object-spread": "warn", + "no-mixed-operators": "warn", + "space-infix-ops": "warn", + "comma-spacing": "warn", + "no-path-concat": "warn", + "semi": "off", + + "@typescript-eslint/promise-function-async": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-unsafe-call": "error", + "@typescript-eslint/no-unsafe-member-access": "error", + "@typescript-eslint/no-unsafe-return": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "warn", + "@typescript-eslint/no-unnecessary-type-assertion": "warn", + "@typescript-eslint/no-unnecessary-condition": "warn", + "@typescript-eslint/no-floating-promises": "warn", + "@typescript-eslint/no-misused-promises": "warn", + "@typescript-eslint/unbound-method": "warn", + "@typescript-eslint/indent": ["warn", 4, { "SwitchCase": 1, "ignoredNodes": [ + "TSTypeAliasDeclaration *", + "TSTypeReference *", + "MemberExpression" + ] }], + "@typescript-eslint/quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }], + "@typescript-eslint/brace-style": ["warn", "stroustrup", { "allowSingleLine": true }], + "@typescript-eslint/semi": ["error"], + "@typescript-eslint/member-delimiter-style": "warn", + "@typescript-eslint/restrict-template-expressions": ["error", { "allowBoolean": true, "allowNumber": true }], + "@typescript-eslint/array-type": ["error", { "default": "generic" }], + "@typescript-eslint/prefer-readonly": "warn", + "@typescript-eslint/prefer-nullish-coalescing": "warn", + "@typescript-eslint/prefer-includes": "warn", + "@typescript-eslint/prefer-string-starts-ends-with": "warn", + "@typescript-eslint/prefer-optional-chain": "warn" + } +} \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/.vscode/settings.json b/.github/actions/create-issues-from-app-insights/.vscode/settings.json new file mode 100644 index 000000000..d09af85bf --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "typescript.tsdk": "./node_modules/typescript/lib", + "editor.codeActionsOnSave": { + "source.fixAll": true + }, + "cSpell.words": [ + "execa" + ] +} \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/action.yml b/.github/actions/create-issues-from-app-insights/action.yml new file mode 100644 index 000000000..77a2a7f31 --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/action.yml @@ -0,0 +1,22 @@ +name: 'Create GitHub Issues from App Insights' +description: 'Creates or updates GitHub issues based on App Insights query results' +inputs: + app-insights-query-path: + description: 'Path to a KQL file containing App Insights query. Query must return "title", "body" and "comment" columns.' + required: true + app-insights-apps: + description: 'Application ID of the App Insights App' + required: true + app-insights-period: + description: 'Time period to query, e.g. 24h.' + required: true + github-label: + description: 'Label that will be applied to the created issues. Note: also used to find issues; changing this later will create duplicates.' + required: true + github-label-cannot-reproduce: + description: 'If an issue is closed and has this label, the issue will be reopened and label removed.' + required: false + +runs: + using: 'node16' + main: 'index.js' \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/index.js b/.github/actions/create-issues-from-app-insights/index.js new file mode 100644 index 000000000..4198e06f2 --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/index.js @@ -0,0 +1,12 @@ +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; +import exec from '@actions/exec'; + +try { + const basePath = dirname(fileURLToPath(import.meta.url)); + await exec.exec(`"${basePath}/node_modules/.bin/ts-node-esm"`, [`${basePath}/index.ts`]); +} +catch (error) { + console.error(error); + process.exit(1); +} \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/index.ts b/.github/actions/create-issues-from-app-insights/index.ts new file mode 100644 index 000000000..a5b03f68e --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/index.ts @@ -0,0 +1,51 @@ +import { promises as fs } from 'fs'; +import * as core from '@actions/core'; +import { Octokit } from '@octokit/rest'; +import { paginateRest } from '@octokit/plugin-paginate-rest'; +import { createActionAuth } from '@octokit/auth-action'; +import { createOrUpdateIssue } from './logic/createOrUpdateIssue.js'; +import { queryAppInsights } from './logic/queryAppInsights.js'; + +const appInsightsQueryPath = core.getInput('app-insights-query-path', { required: true }); +const appInsightsApps = core.getInput('app-insights-apps', { required: true }); +// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition +const appInsightsPeriod = core.getInput('app-insights-period', { required: true }); +const githubLabel = core.getInput('github-label', { required: true }); +const githubCannotReproduceLabel = core.getInput('github-label-cannot-reproduce'); + +const octokit = new (Octokit.plugin(paginateRest))({ + authStrategy: createActionAuth +}); + +const appInsightsData = await queryAppInsights({ + query: await fs.readFile(appInsightsQueryPath, { encoding: 'utf-8' }), + apps: appInsightsApps, + period: appInsightsPeriod +}); + +console.log('Querying GitHub Issues'); +// eslint-disable-next-line @typescript-eslint/no-non-null-assertion +const [owner, repo] = process.env.GITHUB_REPOSITORY!.split('/'); +const issues = await octokit.paginate( + 'GET /repos/{owner}/{repo}/issues', + { + owner, + repo, + state: 'all', + labels: githubLabel, + per_page: 100 + } +); + +console.log('Processing data'); +for (const data of appInsightsData) { + await createOrUpdateIssue({ + data, + issues, + octokit, + owner, + repo, + label: githubLabel, + labelCannotReproduce: githubCannotReproduceLabel + }); +} \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/logic/createOrUpdateIssue.ts b/.github/actions/create-issues-from-app-insights/logic/createOrUpdateIssue.ts new file mode 100644 index 000000000..6f0da00e2 --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/logic/createOrUpdateIssue.ts @@ -0,0 +1,87 @@ +import type { Octokit } from '@octokit/rest'; + +type Issue = Awaited>['data'][number]; +type Context = { + data: { + title: string; + body: string; + comment: string; + }; + + label: string; + labelCannotReproduce: string; + + issues: ReadonlyArray; + octokit: Octokit; + owner: string; + repo: string; +}; + +const findCreateOrReopenIssue = async ({ + data, + + label, + labelCannotReproduce, + + issues, + octokit, + owner, + repo +}: Context) => { + console.log(` ${data.title}`); + + const existing = issues.filter(i => i.title === data.title); + if (existing.length > 1) + throw new Error(`Found multiple issues with title '${data.title}':\n${existing.map(i => ' - ' + i.html_url).join('\n')}`); + + if (existing.length === 0) { + console.log(' - creating'); + const issue = (await octokit.issues.create({ + owner, + repo, + title: data.title, + body: data.body, + labels: [label] + })).data; + console.log(` - ${issue.html_url}`); + return issue; + } + + const issue = existing[0]; + console.log(` - found at ${issue.url}`); + + const isClosedAsNotReproducible = labelCannotReproduce + && issue.state === 'CLOSED' + && issue.labels.some(l => typeof l === 'object' && l.name === labelCannotReproduce); + if (isClosedAsNotReproducible) { + console.log(' - reopening'); + await octokit.issues.update({ + owner, + repo, + issue_number: issue.number, + state: 'open' + }); + console.log(` - removing ${labelCannotReproduce}`); + await octokit.issues.removeLabel({ + owner, + repo, + issue_number: issue.number, + name: labelCannotReproduce + }); + } + + return issue; +}; + +export const createOrUpdateIssue = async (context: Context) => { + const issue = await findCreateOrReopenIssue(context); + const { data, octokit, owner, repo } = context; + console.log(' - commenting'); + const comment = (await octokit.issues.createComment({ + owner, + repo, + issue_number: issue.number, + body: data.comment + })).data; + console.log(` - ${comment.html_url}`); +}; \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/logic/queryAppInsights.ts b/.github/actions/create-issues-from-app-insights/logic/queryAppInsights.ts new file mode 100644 index 000000000..b215cdfdc --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/logic/queryAppInsights.ts @@ -0,0 +1,45 @@ +import { execa } from 'execa'; + +type Column = { name: string }; + +export const queryAppInsights = async ({ + query, + apps, + period +}: { + query: string; + apps: string; + period: string; +}) => { + console.log('Querying App Insights'); + const { columns, rows } = (JSON.parse((await execa('az', [ + 'monitor', 'app-insights', 'query', + '--analytics-query', query.replace(/[\r\n]+/g, ' '), + '--apps', apps, + '--offset', period + ], { + stderr: process.stderr + })).stdout) as { + tables: ReadonlyArray<{ + columns: ReadonlyArray; + rows: ReadonlyArray>; + }>; + }).tables[0]; + + const columnIndexOf = (name: string) => { + const index = columns.findIndex(c => c.name === name); + if (index < 0) + throw new Error(`Could not find column '${name}' in App Insights output. Found columns: ${columns.map(c => c.name).join(', ')}.`); + return index; + }; + + const titleColumnIndex = columnIndexOf('title'); + const bodyColumnIndex = columnIndexOf('body'); + const commentColumnIndex = columnIndexOf('comment'); + + return rows.map(r => ({ + title: r[titleColumnIndex], + body: r[bodyColumnIndex], + comment: r[commentColumnIndex] + })); +}; \ No newline at end of file diff --git a/.github/actions/create-issues-from-app-insights/package-lock.json b/.github/actions/create-issues-from-app-insights/package-lock.json new file mode 100644 index 000000000..a49469c42 --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/package-lock.json @@ -0,0 +1,3353 @@ +{ + "name": "create-issues-from-app-insights", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "create-issues-from-app-insights", + "version": "1.0.0", + "dependencies": { + "@actions/core": "^1.8.2", + "@actions/exec": "^1.1.1", + "@octokit/auth-action": "^1.3.3", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/rest": "^18.12.0", + "execa": "^6.1.0", + "ts-node": "^10.8.0", + "typescript": "^4.7.2" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.26.0", + "@typescript-eslint/parser": "^5.26.0", + "dotenv": "^16.0.1", + "eslint": "^8.16.0" + } + }, + "node_modules/@actions/core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", + "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "dependencies": { + "@actions/http-client": "^2.0.1" + } + }, + "node_modules/@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "dependencies": { + "@actions/io": "^1.0.1" + } + }, + "node_modules/@actions/http-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "dependencies": { + "tunnel": "^0.0.6" + } + }, + "node_modules/@actions/io": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-action": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-1.3.3.tgz", + "integrity": "sha512-8v4c/pw6HTxsF7pCgJoox/q4KKov4zkgLxEGGqLOZPSZaHf1LqdLlj5m5x5c1bKNn38uQXNvJKEnKX1qJlGeQQ==", + "dependencies": { + "@octokit/auth-token": "^2.4.0", + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "dependencies": { + "@octokit/types": "^6.0.3" + } + }, + "node_modules/@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "dependencies": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "dependencies": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "dependencies": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", + "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", + "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "dependencies": { + "@octokit/types": "^6.34.0" + }, + "peerDependencies": { + "@octokit/core": ">=2" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", + "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "dependencies": { + "@octokit/types": "^6.34.0", + "deprecation": "^2.3.1" + }, + "peerDependencies": { + "@octokit/core": ">=3" + } + }, + "node_modules/@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "dependencies": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "node_modules/@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "dependencies": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "node_modules/@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "dependencies": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "node_modules/@octokit/types": { + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", + "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "dependencies": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", + "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==", + "peer": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", + "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/type-utils": "5.26.0", + "@typescript-eslint/utils": "5.26.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz", + "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.26.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz", + "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.26.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/before-after-hook": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==", + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "node_modules/ts-node": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", + "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@actions/core": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.8.2.tgz", + "integrity": "sha512-FXcBL7nyik8K5ODeCKlxi+vts7torOkoDAKfeh61EAkAy1HAvwn9uVzZBY0f15YcQTcZZ2/iSGBFHEuioZWfDA==", + "requires": { + "@actions/http-client": "^2.0.1" + } + }, + "@actions/exec": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz", + "integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==", + "requires": { + "@actions/io": "^1.0.1" + } + }, + "@actions/http-client": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz", + "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==", + "requires": { + "tunnel": "^0.0.6" + } + }, + "@actions/io": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.2.tgz", + "integrity": "sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw==" + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@octokit/auth-action": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@octokit/auth-action/-/auth-action-1.3.3.tgz", + "integrity": "sha512-8v4c/pw6HTxsF7pCgJoox/q4KKov4zkgLxEGGqLOZPSZaHf1LqdLlj5m5x5c1bKNn38uQXNvJKEnKX1qJlGeQQ==", + "requires": { + "@octokit/auth-token": "^2.4.0", + "@octokit/types": "^6.0.3" + } + }, + "@octokit/auth-token": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz", + "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==", + "requires": { + "@octokit/types": "^6.0.3" + } + }, + "@octokit/core": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz", + "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==", + "requires": { + "@octokit/auth-token": "^2.4.4", + "@octokit/graphql": "^4.5.8", + "@octokit/request": "^5.6.3", + "@octokit/request-error": "^2.0.5", + "@octokit/types": "^6.0.3", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/endpoint": { + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz", + "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==", + "requires": { + "@octokit/types": "^6.0.3", + "is-plain-object": "^5.0.0", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/graphql": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz", + "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==", + "requires": { + "@octokit/request": "^5.6.0", + "@octokit/types": "^6.0.3", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/openapi-types": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz", + "integrity": "sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA==" + }, + "@octokit/plugin-paginate-rest": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.17.0.tgz", + "integrity": "sha512-tzMbrbnam2Mt4AhuyCHvpRkS0oZ5MvwwcQPYGtMv4tUa5kkzG58SVB0fcsLulOZQeRnOgdkZWkRUiyBlh0Bkyw==", + "requires": { + "@octokit/types": "^6.34.0" + } + }, + "@octokit/plugin-request-log": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz", + "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==", + "requires": {} + }, + "@octokit/plugin-rest-endpoint-methods": { + "version": "5.13.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.13.0.tgz", + "integrity": "sha512-uJjMTkN1KaOIgNtUPMtIXDOjx6dGYysdIFhgA52x4xSadQCz3b/zJexvITDVpANnfKPW/+E0xkOvLntqMYpviA==", + "requires": { + "@octokit/types": "^6.34.0", + "deprecation": "^2.3.1" + } + }, + "@octokit/request": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz", + "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==", + "requires": { + "@octokit/endpoint": "^6.0.1", + "@octokit/request-error": "^2.1.0", + "@octokit/types": "^6.16.1", + "is-plain-object": "^5.0.0", + "node-fetch": "^2.6.7", + "universal-user-agent": "^6.0.0" + } + }, + "@octokit/request-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz", + "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==", + "requires": { + "@octokit/types": "^6.0.3", + "deprecation": "^2.0.0", + "once": "^1.4.0" + } + }, + "@octokit/rest": { + "version": "18.12.0", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-18.12.0.tgz", + "integrity": "sha512-gDPiOHlyGavxr72y0guQEhLsemgVjwRePayJ+FcKc2SJqKUbxbkvf5kAZEWA/MKvsfYlQAMVzNJE3ezQcxMJ2Q==", + "requires": { + "@octokit/core": "^3.5.1", + "@octokit/plugin-paginate-rest": "^2.16.8", + "@octokit/plugin-request-log": "^1.0.4", + "@octokit/plugin-rest-endpoint-methods": "^5.12.0" + } + }, + "@octokit/types": { + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz", + "integrity": "sha512-s1zLBjWhdEI2zwaoSgyOFoKSl109CUcVBCc7biPJ3aAf6LGLU6szDvi31JPU7bxfla2lqfhjbbg/5DdFNxOwHw==", + "requires": { + "@octokit/openapi-types": "^11.2.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/node": { + "version": "17.0.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", + "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==", + "peer": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.26.0.tgz", + "integrity": "sha512-oGCmo0PqnRZZndr+KwvvAUvD3kNE4AfyoGCwOZpoCncSh4MVD06JTE8XQa2u9u+NX5CsyZMBTEc2C72zx38eYA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/type-utils": "5.26.0", + "@typescript-eslint/utils": "5.26.0", + "debug": "^4.3.4", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.2.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.26.0.tgz", + "integrity": "sha512-n/IzU87ttzIdnAH5vQ4BBDnLPly7rC5VnjN3m0xBG82HK6rhRxnCb3w/GyWbNDghPd+NktJqB/wl6+YkzZ5T5Q==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.26.0.tgz", + "integrity": "sha512-gVzTJUESuTwiju/7NiTb4c5oqod8xt5GhMbExKsCTp6adU3mya6AGJ4Pl9xC7x2DX9UYFsjImC0mA62BCY22Iw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.26.0.tgz", + "integrity": "sha512-7ccbUVWGLmcRDSA1+ADkDBl5fP87EJt0fnijsMFTVHXKGduYMgienC/i3QwoVhDADUAPoytgjbZbCOMj4TY55A==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.26.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.26.0.tgz", + "integrity": "sha512-8794JZFE1RN4XaExLWLI2oSXsVImNkl79PzTOOWt9h0UHROwJedNOD2IJyfL0NbddFllcktGIO2aOu10avQQyA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.26.0.tgz", + "integrity": "sha512-EyGpw6eQDsfD6jIqmXP3rU5oHScZ51tL/cZgFbFBvWuCwrIptl+oueUZzSmLtxFuSOQ9vDcJIs+279gnJkfd1w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/visitor-keys": "5.26.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.26.0.tgz", + "integrity": "sha512-PJFwcTq2Pt4AMOKfe3zQOdez6InIDOjUJJD3v3LyEtxHGVVRK3Vo7Dd923t/4M9hSH2q2CLvcTdxlLPjcIk3eg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.26.0", + "@typescript-eslint/types": "5.26.0", + "@typescript-eslint/typescript-estree": "5.26.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.26.0.tgz", + "integrity": "sha512-wei+ffqHanYDOQgg/fS6Hcar6wAWv0CUPQ3TZzOWd2BLfgP539rb49bwua8WRAs7R6kOSLn82rfEu2ro6Llt8Q==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.26.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "before-after-hook": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.2.tgz", + "integrity": "sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "requires": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "execa": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz", + "integrity": "sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.1", + "human-signals": "^3.0.1", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "human-signals": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", + "integrity": "sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==" + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" + }, + "is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "npm-run-path": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "requires": { + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==" + } + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "requires": { + "mimic-fn": "^4.0.0" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==" + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + }, + "ts-node": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.0.tgz", + "integrity": "sha512-/fNd5Qh+zTt8Vt1KbYZjRHCE9sI5i7nqfD/dzBBRDeVXZXS6kToW6R7tTU6Nd4XavFs0mAVCg29Q//ML7WsZYA==", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", + "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==" + }, + "universal-user-agent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==" + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + } + } +} diff --git a/.github/actions/create-issues-from-app-insights/package.json b/.github/actions/create-issues-from-app-insights/package.json new file mode 100644 index 000000000..aeff87350 --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/package.json @@ -0,0 +1,26 @@ +{ + "private": true, + "name": "create-issues-from-app-insights", + "version": "1.0.0", + "description": "", + "type": "module", + "scripts": { + "local": "node -r dotenv/config index.js" + }, + "dependencies": { + "@actions/core": "^1.8.2", + "@actions/exec": "^1.1.1", + "@octokit/auth-action": "^1.3.3", + "@octokit/plugin-paginate-rest": "^2.17.0", + "@octokit/rest": "^18.12.0", + "execa": "^6.1.0", + "ts-node": "^10.8.0", + "typescript": "^4.7.2" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.26.0", + "@typescript-eslint/parser": "^5.26.0", + "dotenv": "^16.0.1", + "eslint": "^8.16.0" + } +} diff --git a/.github/actions/create-issues-from-app-insights/tsconfig.json b/.github/actions/create-issues-from-app-insights/tsconfig.json new file mode 100644 index 000000000..8dd59121c --- /dev/null +++ b/.github/actions/create-issues-from-app-insights/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2019", + "module": "ES2022", + "moduleResolution": "node", + "noEmit": true, + "strict": true, + "noImplicitAny": true, + "importsNotUsedAsValues": "error", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "include": [ + "logic", + "*.ts" + ] +} \ No newline at end of file diff --git a/.github/actions/deploy-artifact-to-azure-windows-vm/action.yml b/.github/actions/deploy-artifact-to-azure-windows-vm/action.yml index b665a5553..6ea79ced1 100644 --- a/.github/actions/deploy-artifact-to-azure-windows-vm/action.yml +++ b/.github/actions/deploy-artifact-to-azure-windows-vm/action.yml @@ -21,5 +21,5 @@ inputs: required: true runs: - using: 'node12' + using: 'node16' main: 'index.js' \ No newline at end of file diff --git a/.github/workflows/.vscode/settings.json b/.github/workflows/.vscode/settings.json new file mode 100644 index 000000000..c0220a985 --- /dev/null +++ b/.github/workflows/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "cSpell.words": [ + "azcliversion", + "Brunner", + "creds", + "isnotempty", + "Kusto", + "mirrorsharp", + "msbuild", + "netfx", + "pwsh", + "SHARPLAB", + "slpublic", + "startswith", + "strcat", + "tostring", + "webapps" + ] +} \ No newline at end of file diff --git a/.github/workflows/container-host-edge.yml b/.github/workflows/container-host-edge.yml index b68084e7d..aab9fa7f0 100644 --- a/.github/workflows/container-host-edge.yml +++ b/.github/workflows/container-host-edge.yml @@ -14,18 +14,20 @@ on: jobs: build: - name: 'Build (.NET 6)' + name: 'Build (.NET 9)' # https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012/5 if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository runs-on: windows-latest + env: + NUGET_PACKAGES: ${{github.workspace}}/.nuget/packages steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'true' - - uses: actions/setup-dotnet@v1 + - uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x - - uses: microsoft/setup-msbuild@v1.0.2 + dotnet-version: 9.0.x + - uses: microsoft/setup-msbuild@v1.1 # https://github.com/actions/setup-dotnet/issues/155 - run: dotnet nuget locals all --clear @@ -33,14 +35,22 @@ jobs: # https://github.com/dotnet/sdk/issues/13281 - run: dotnet nuget add source https://ci.appveyor.com/nuget/vanara-prerelease + - uses: actions/cache@v3 + with: + path: ${{github.workspace}}/.nuget/packages + key: nuget-container-host-${{hashFiles('**/*.csproj')}} + # can restore caches from server as well, but should not overwrite them + restore-keys: | + nuget- + #- run: msbuild source/Native.Profiler/Native.Profiler.vcxproj /p:SolutionName=SharpLab /p:Configuration=Release /p:Platform=x64 - run: dotnet build source/Tests --configuration Release - run: dotnet test source/Tests --no-build --configuration Release - run: dotnet publish source/Container.Manager --no-build --configuration Release - - run: Compress-Archive -Path 'source/Container.Manager/bin/Release/net6.0/publish/*' -DestinationPath 'Container.Manager.zip' + - run: Compress-Archive -Path 'source/Container.Manager/bin/Release/net9.0/publish/*' -DestinationPath 'Container.Manager.zip' shell: pwsh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: Container.Manager path: Container.Manager.zip @@ -48,13 +58,15 @@ jobs: deploy: name: 'Deploy (Edge)' runs-on: ubuntu-latest + permissions: + id-token: write needs: build if: github.ref == 'refs/heads/main' environment: edge-container-host steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - run: 'git show ${{ github.sha }} --format="::set-output name=version_number::%cd" --date=format:%Y-%m-%d-%H%M --no-patch' + - run: 'git show ${{ github.sha }} --format="version_number=%cd" --date=format:%Y-%m-%d-%H%M --no-patch >> $GITHUB_OUTPUT' id: version - run: npm ci @@ -62,7 +74,9 @@ jobs: - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - uses: ./.github/actions/deploy-artifact-to-azure-windows-vm with: diff --git a/.github/workflows/exceptions/query.kql b/.github/workflows/exceptions/query.kql new file mode 100644 index 000000000..b7bd72d45 --- /dev/null +++ b/.github/workflows/exceptions/query.kql @@ -0,0 +1,50 @@ +exceptions + | where client_Type != 'Browser' + | where type !startswith 'Unbreakable' + | where not (type == 'System.NotSupportedException' and ( + assembly startswith 'SharpLab' + or + outerMessage has 'not supported by SharpLab' + )) + | where outerType !in ( + 'MirrorSharp.Advanced.EarlyAccess.RoslynSourceTextGuardException', + 'MirrorSharp.Advanced.EarlyAccess.RoslynCompilationGuardException', + 'SharpLab.Runtime.Internal.JitGenericAttributeException' + ) + | extend containerType = iif(type == 'System.Exception', extract('Container host repor?ted an error:[\\r\\n]*([^:]+)', 1, outerMessage), '') + | where containerType != 'SharpLab.Container.Manager.Internal.ContainerAllocationException' + | extend containerMethod = iif(isnotempty(containerType), extract('[\\r\\n]+\\s*at ([^(]+)', 1, outerMessage), '') + | project itemCount, + app=tostring(customDimensions['Web App']), + type=coalesce(containerType, type), + method=case( + type == 'System.OutOfMemoryException', '', + type == 'System.InvalidProgramException', '', + coalesce(containerMethod, method) + ), + query=strcat( + 'exceptions\n | where type == \'', type, + iif( + type !in ('System.OutOfMemoryException', 'System.InvalidProgramException'), + strcat('\'\n | where method == \'', method, '\''), + '' + ), + iif(isnotempty(containerType), strcat('\n | where outerMessage contains \'', containerType, '\''), '') + ) + | summarize _count=sum(itemCount) by type, method, query, app + | summarize countRows=make_list(strcat('| ', app, ' | ', _count, ' |'), 100), + countTotal=sum(_count) by type, method, query + | project title=strcat(type, ' at ', method), + body=strcat( + 'AppInsights query:\n', + '```Kusto\n', + query, + '\n```' + ), + comment=strcat( + '| App | Count (last 24h) |\n', + '| ------------- | ------------- |\n', + strcat_array(countRows, '\n'), '\n', + '| Total | ', countTotal, ' |' + ) + | take 150 \ No newline at end of file diff --git a/.github/workflows/issues-exceptions.yml b/.github/workflows/issues-exceptions.yml index e68d00e3b..e2e632861 100644 --- a/.github/workflows/issues-exceptions.yml +++ b/.github/workflows/issues-exceptions.yml @@ -10,14 +10,23 @@ jobs: name: 'Analyze and report exceptions' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 + + - run: npm ci + working-directory: ./.github/actions/create-issues-from-app-insights + - uses: azure/login@v1 with: creds: ${{ secrets.AZURE_CREDENTIALS }} - run: az extension add --name application-insights - - run: ./#scripts/github-actions/New-IssuesFromAppInsightsExceptions.ps1 + - uses: ./.github/actions/create-issues-from-app-insights + with: + app-insights-query-path: './.github/workflows/exceptions/query.kql' + app-insights-apps: 'f33db8a2-47c9-48ea-81c4-8f431f8fd1f9' + app-insights-period: '24h' + github-label: ':boom: exception' + github-label-cannot-reproduce: '✖ cannot reproduce' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: pwsh \ No newline at end of file diff --git a/.github/workflows/roslyn-branches.yml b/.github/workflows/roslyn-branches.yml index 518716b1f..5c95d1311 100644 --- a/.github/workflows/roslyn-branches.yml +++ b/.github/workflows/roslyn-branches.yml @@ -4,6 +4,10 @@ on: schedule: - cron: '0 12 * * *' workflow_dispatch: + inputs: + filter: + type: string + description: Branch name filter defaults: run: @@ -11,48 +15,74 @@ defaults: jobs: generate-matrix: + name: Generate Run Matrix runs-on: windows-latest outputs: - matrix: ${{steps.generate-matrix.outputs.matrix}} + update: ${{steps.generate-matrix.outputs.update}} + cleanup: ${{steps.generate-matrix.outputs.cleanup}} steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: - node-version: '12.16.1' - - name: npm ci - run: | - npm ci + node-version: '20.14.0' + - run: npm ci + - run: npm run check - id: generate-matrix - name: generate run matrix - run: | - npm run generate-run-matrix + run: npm run generate-matrix + env: + SL_BRANCH_FILTER: ${{ github.event.inputs.filter }} + SL_DEPLOY_MODE: Azure + SL_BUILD_AZURE_TENANT: ${{secrets.AzureTenant}} + SL_BUILD_AZURE_APP_ID: ${{secrets.AzureAppID}} + SL_BUILD_AZURE_SECRET: ${{secrets.AzureSecret}} - build-branch: + update-branch: + name: ${{matrix.branch}} (update) needs: generate-matrix runs-on: windows-latest strategy: - matrix: ${{fromJson(needs.generate-matrix.outputs.matrix)}} + matrix: ${{fromJson(needs.generate-matrix.outputs.update)}} fail-fast: false continue-on-error: ${{matrix.optional}} steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 with: submodules: true - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: - node-version: '12.16.1' - - uses: actions/setup-dotnet@v1 + node-version: '20.14.0' + - uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x - - name: npm ci - run: | - npm ci - - name: build branch + dotnet-version: 9.0.x + - run: npm ci + - run: npm run update-branch -- ${{matrix.branch}} env: SHARPLAB_TELEMETRY_KEY: ${{secrets.AzureBranchTelemetryKey}} SL_DEPLOY_MODE: Azure SL_BUILD_AZURE_TENANT: ${{secrets.AzureTenant}} SL_BUILD_AZURE_APP_ID: ${{secrets.AzureAppID}} SL_BUILD_AZURE_SECRET: ${{secrets.AzureSecret}} - run: | - npm run build-branch -- ${{matrix.branch}} \ No newline at end of file + + cleanup-branch: + name: ${{matrix.branch}} (cleanup) + needs: generate-matrix + runs-on: windows-latest + continue-on-error: ${{matrix.optional}} + if: ${{ needs.generate-matrix.outputs.cleanup != '' && toJson(fromJson(needs.generate-matrix.outputs.cleanup)) != '[]' }} + strategy: + matrix: ${{fromJson(needs.generate-matrix.outputs.cleanup)}} + fail-fast: false + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - uses: actions/setup-node@v3 + with: + node-version: '20.14.0' + - run: npm ci + - run: npm run cleanup-branch -- ${{matrix.branch}} ${{matrix.action}} + env: + SL_DEPLOY_MODE: Azure + SL_BUILD_AZURE_TENANT: ${{secrets.AzureTenant}} + SL_BUILD_AZURE_APP_ID: ${{secrets.AzureAppID}} + SL_BUILD_AZURE_SECRET: ${{secrets.AzureSecret}} \ No newline at end of file diff --git a/.github/workflows/server-edge.yml b/.github/workflows/server-edge.yml index a84fcf88c..3482e2759 100644 --- a/.github/workflows/server-edge.yml +++ b/.github/workflows/server-edge.yml @@ -9,27 +9,39 @@ on: - '!source/Container/**' - '!source/Container.Manager/**' - '!source/#external/Fragile/**' + - '!source/#external/mirrorsharp/WebAssets/**' + - '!source/#external/mirrorsharp-codemirror-6-preview/WebAssets/**' pull_request: workflow_dispatch: jobs: build-core: - name: 'Build (.NET 6)' + name: 'Build (.NET 9)' # https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012/5 if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository runs-on: windows-latest + env: + NUGET_PACKAGES: ${{github.workspace}}/.nuget/packages steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'true' - - uses: actions/setup-dotnet@v1 + - uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x - - uses: microsoft/setup-msbuild@v1.0.2 + dotnet-version: 9.0.x + - uses: microsoft/setup-msbuild@v1.1 # https://github.com/actions/setup-dotnet/issues/155 - run: dotnet nuget locals all --clear + - uses: actions/cache@v3 + with: + path: ${{github.workspace}}/.nuget/packages + key: nuget-server-${{hashFiles('**/*.csproj')}} + # can restore caches from container-host as well, but should not overwrite them + restore-keys: | + nuget- + # https://github.com/dotnet/sdk/issues/13281 - run: dotnet nuget add source https://ci.appveyor.com/nuget/vanara-prerelease @@ -40,16 +52,16 @@ jobs: - run: dotnet test source/Tests --no-build --configuration Release - run: dotnet publish source/Server --no-build --configuration Release - run: dotnet publish source/WebApp.Server --no-build --configuration Release /p:ErrorOnDuplicatePublishOutputFiles=false - - run: Compress-Archive -Path 'source/Server/bin/Release/net6.0/publish/*' -DestinationPath 'Server.zip' + - run: Compress-Archive -Path 'source/Server/bin/Release/net9.0/publish/*' -DestinationPath 'Server.zip' shell: pwsh - - run: Compress-Archive -Path 'source/WebApp.Server/bin/Release/net6.0/publish/*' -DestinationPath 'WebApp.Server.zip' + - run: Compress-Archive -Path 'source/WebApp.Server/bin/Release/net9.0/publish/*' -DestinationPath 'WebApp.Server.zip' shell: pwsh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: Server path: Server.zip - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: WebApp.Server path: WebApp.Server.zip @@ -70,34 +82,24 @@ jobs: environment: edge-server-x64 name: 'Deploy to Edge (${{ matrix.name }})' runs-on: ubuntu-latest + permissions: + id-token: write needs: build-core if: github.ref == 'refs/heads/main' environment: ${{ matrix.environment }} steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: ${{ matrix.artifact }} - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - # https://github.com/Azure/webapps-deploy/issues/100 - - name: "Run azure/CLI@v1: az webapp stop" - uses: azure/CLI@v1 - with: - azcliversion: 2.30.0 - inlineScript: az webapp stop --name ${{ matrix.app }} --resource-group SharpLab - # https://github.com/Azure/webapps-deploy/issues/100#issuecomment-754368190 - - run: Start-Sleep -Seconds 10 - shell: pwsh + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - uses: azure/webapps-deploy@v2 with: app-name: ${{ matrix.app }} package: ${{ matrix.artifact }}.zip - - name: "Run azure/CLI@v1: az webapp start" - uses: azure/CLI@v1 - with: - azcliversion: 2.30.0 - inlineScript: az webapp start --name ${{ matrix.app }} --resource-group SharpLab - run: Invoke-RestMethod "${{ matrix.url }}" -MaximumRetryCount 10 -RetryIntervalSec 2 shell: pwsh @@ -107,12 +109,12 @@ jobs: if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: 'true' - - uses: actions/setup-dotnet@v1 + - uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x + dotnet-version: 9.0.x # https://github.com/actions/setup-dotnet/issues/155 - run: dotnet nuget locals all --clear @@ -123,7 +125,7 @@ jobs: - run: Compress-Archive -Path 'source/NetFramework/Server/bin/publish/*' -DestinationPath 'Server.NetFramework.zip' shell: pwsh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: Server.NetFramework path: Server.NetFramework.zip @@ -142,16 +144,20 @@ jobs: environment: edge-server-netfx-x64 name: 'Deploy to Edge (${{ matrix.name }})' runs-on: ubuntu-latest + permissions: + id-token: write needs: build-netfx if: github.ref == 'refs/heads/main' environment: ${{ matrix.environment }} steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: Server.NetFramework - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - uses: azure/webapps-deploy@v2 with: app-name: ${{ matrix.app }} @@ -165,17 +171,19 @@ jobs: create-release: name: 'Create Release' runs-on: ubuntu-latest + permissions: + contents: write needs: - deploy-core - deploy-netfx if: github.ref == 'refs/heads/main' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - run: 'git show ${{ github.sha }} --format="::set-output name=version_number::%cd" --date=format:%Y-%m-%d-%H%M --no-patch' + - run: 'git show ${{ github.sha }} --format="version_number=%cd" --date=format:%Y-%m-%d-%H%M --no-patch >> $GITHUB_OUTPUT' id: version - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 - uses: actions/create-release@v1 id: create_release diff --git a/.github/workflows/server-main.yml b/.github/workflows/server-main.yml index cd7f582d7..6cef5b0a3 100644 --- a/.github/workflows/server-main.yml +++ b/.github/workflows/server-main.yml @@ -10,36 +10,34 @@ jobs: - name: 'WebApp Server / Default' package: WebApp.Server.zip app: sharplab - stop-app: true url: https://sharplab.io environment: main-server - name: x64 package: Server.zip app: sl-a-core-x64 - stop-app: true url: https://sl-a-core-x64.azurewebsites.net/status environment: main-server-x64 - name: '.NET Framework, x86' package: Server.NetFramework.zip app: sl-a-netfx - stop-app: false url: https://sl-a-netfx.azurewebsites.net/status environment: main-server-netfx - name: '.NET Framework, x64' package: Server.NetFramework.zip app: sl-a-netfx-x64 - stop-app: false url: https://sl-a-netfx-x64.azurewebsites.net/status environment: main-server-netfx-x64 name: 'Deploy to Main (${{ matrix.name }})' runs-on: ubuntu-latest + permissions: + id-token: write environment: ${{ matrix.environment }} steps: - - uses: actions/github-script@v3 + - uses: actions/github-script@v6 id: get-release-tag with: script: | @@ -61,32 +59,14 @@ jobs: - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - # https://github.com/Azure/webapps-deploy/issues/100 - - name: "Run azure/CLI@v1: az webapp stop" - if: matrix.stop-app - uses: azure/CLI@v1 - with: - azcliversion: 2.30.0 - inlineScript: az webapp stop --name ${{ matrix.app }} --resource-group SharpLab - - # https://github.com/Azure/webapps-deploy/issues/100#issuecomment-754368190 - - run: Start-Sleep -Seconds 10 - if: matrix.stop-app - shell: pwsh + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - uses: azure/webapps-deploy@v2 with: app-name: ${{ matrix.app }} package: ${{ matrix.package }} - - name: "Run azure/CLI@v1: az webapp start" - uses: azure/CLI@v1 - if: matrix.stop-app - with: - azcliversion: 2.30.0 - inlineScript: az webapp start --name ${{ matrix.app }} --resource-group SharpLab - - run: Invoke-RestMethod "${{ matrix.url }}" -MaximumRetryCount 10 -RetryIntervalSec 2 shell: pwsh \ No newline at end of file diff --git a/.github/workflows/webapp-edge.yml b/.github/workflows/webapp-edge.yml index 605151834..385a4c3ed 100644 --- a/.github/workflows/webapp-edge.yml +++ b/.github/workflows/webapp-edge.yml @@ -5,6 +5,8 @@ on: paths: - '.github/workflows/webapp-edge.yml' - 'source/WebApp/**' + - 'source/#external/mirrorsharp/WebAssets/**' + - 'source/#external/mirrorsharp-codemirror-6-preview/WebAssets/**' pull_request: workflow_dispatch: @@ -14,19 +16,27 @@ jobs: # https://github.community/t/duplicate-checks-on-push-and-pull-request-simultaneous-event/18012/5 if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository runs-on: ubuntu-latest + permissions: + contents: write defaults: run: working-directory: source/WebApp steps: - - uses: actions/checkout@v2 + - run: git config --global core.autocrlf false + working-directory: /home + + - uses: actions/checkout@v3 with: submodules: 'true' + lfs: 'true' + + - run: git lfs checkout - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: - node-version: '16.14.2' + node-version: '20.14.0' - - run: 'git show ${{ github.sha }} --format="::set-output name=version_number::%cd" --date=format:%Y-%m-%d-%H%M --no-patch' + - run: 'git show ${{ github.sha }} --format="version_number=%cd" --date=format:%Y-%m-%d-%H%M --no-patch >> $GITHUB_OUTPUT' id: version - name: Run npm ci (mirrorsharp) @@ -37,6 +47,14 @@ jobs: run: npm run build working-directory: source/#external/mirrorsharp/WebAssets + - name: Run npm ci (mirrorsharp-codemirror-6-preview) + run: npm ci + working-directory: source/#external/mirrorsharp-codemirror-6-preview/WebAssets + + - name: Run npm run build (mirrorsharp-codemirror-6-preview) + run: npm run build + working-directory: source/#external/mirrorsharp-codemirror-6-preview/WebAssets + - run: npm ci - run: npm run build-ci @@ -45,40 +63,56 @@ jobs: SHARPLAB_WEBAPP_BUILD_VERSION: ${{ steps.version.outputs.version_number }} - run: npm run test - - run: npm run test-storybook-ci - - uses: actions/upload-artifact@v2 + - run: npm run build-storybook + env: + NODE_ENV: test + - run: npm run test-storybook + + - name: "[Failure] Run actions/upload-artifact@v3 (diff output)" + uses: actions/upload-artifact@v3 + if: failure() + with: + name: __diff_output__ + path: source/WebApp/app/**/__snapshots__/**/__diff_output__/**/*.* + if-no-files-found: ignore + + - name: "[Failure] Run npm run test-storybook-update" + run: npm run test-storybook-update + if: failure() + + - name: "[Failure] Run actions/upload-artifact@v3 (updated snapshots)" + uses: actions/upload-artifact@v3 + if: failure() + with: + name: '__snapshots__ (updated)' + path: source/WebApp/app/**/__snapshots__/**/*.* + if-no-files-found: ignore + + - uses: actions/upload-artifact@v3 with: name: WebApp path: source/WebApp/WebApp.zip if-no-files-found: error - - uses: actions/create-release@v1 + - uses: ncipollo/release-action@b072aaafe138c5ecf1c39f714a76bce6f0d0bc9c if: github.ref == 'refs/heads/main' id: create_release with: - tag_name: webapp-release-${{ steps.version.outputs.version_number }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - uses: actions/upload-release-asset@v1 - if: github.ref == 'refs/heads/main' - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./source/WebApp/WebApp.zip - asset_name: WebApp.zip - asset_content_type: application/zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + artifacts: ./source/WebApp/WebApp.zip + artifactContentType: application/zip + tag: webapp-release-${{ steps.version.outputs.version_number }} deploy-to-edge: name: Deploy (Edge) needs: build - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/feature/execution-flow-output-squashed' environment: edge-webapp runs-on: ubuntu-latest + permissions: + id-token: write steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 with: name: WebApp @@ -90,10 +124,12 @@ jobs: - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - name: "Run azure/CLI@v1: az storage blob upload-batch" - uses: azure/CLI@v1 + - name: "Run azure/CLI@e43928ebbc386700c6bb2f42a97a8de31576cfd2: az storage blob upload-batch" + uses: azure/CLI@e43928ebbc386700c6bb2f42a97a8de31576cfd2 with: azcliversion: 2.30.0 inlineScript: | diff --git a/.github/workflows/webapp-main.yml b/.github/workflows/webapp-main.yml index 777b65c37..dd1b7d032 100644 --- a/.github/workflows/webapp-main.yml +++ b/.github/workflows/webapp-main.yml @@ -7,13 +7,17 @@ jobs: name: Deploy (Main) environment: main-webapp runs-on: ubuntu-latest + permissions: + id-token: write steps: - uses: azure/login@v1 with: - creds: ${{ secrets.AZURE_CREDENTIALS }} + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} - - name: "Run azure/CLI@v1: az storage copy" - uses: azure/CLI@v1 + - name: "Run azure/CLI@e43928ebbc386700c6bb2f42a97a8de31576cfd2: az storage copy" + uses: azure/CLI@e43928ebbc386700c6bb2f42a97a8de31576cfd2 with: azcliversion: 2.30.0 inlineScript: | diff --git a/.gitmodules b/.gitmodules index dbc436496..0c3252502 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,15 @@ -[submodule "source/Tests/TestData/language-syntax-explanations"] - path = source/Tests/TestData/language-syntax-explanations - url = https://github.com/ashmind/language-syntax-explanations.git -[submodule "source/#external/SourcePath"] - path = "source/#external/SourcePath" - url = https://github.com/ashmind/SourcePath.git -[submodule "source/#external/mirrorsharp"] - path = "source/#external/mirrorsharp" - url = https://github.com/ashmind/mirrorsharp -[submodule "source/#external/Mobius.ILasm"] - path = "source/#external/Mobius.ILasm" - url = https://github.com/ashmind/Mobius.ILasm +[submodule "source/Tests/TestData/language-syntax-explanations"] + path = source/Tests/TestData/language-syntax-explanations + url = https://github.com/ashmind/language-syntax-explanations.git +[submodule "source/#external/SourcePath"] + path = "source/#external/SourcePath" + url = https://github.com/ashmind/SourcePath.git +[submodule "source/#external/mirrorsharp"] + path = "source/#external/mirrorsharp" + url = https://github.com/ashmind/mirrorsharp +[submodule "source/#external/Mobius.ILasm"] + path = "source/#external/Mobius.ILasm" + url = https://github.com/ashmind/Mobius.ILasm +[submodule "source/#external/mirrorsharp-codemirror-6-preview"] + path = "source/#external/mirrorsharp-codemirror-6-preview" + url = https://github.com/ashmind/mirrorsharp.git diff --git a/global.json b/global.json index dfe38a680..b2934c71f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100", + "version": "9.0.100", "rollForward": "latestFeature" } } diff --git a/source/#external/Fragile/Fragile/Fragile.csproj b/source/#external/Fragile/Fragile/Fragile.csproj index 1da32ae77..9512dc761 100644 --- a/source/#external/Fragile/Fragile/Fragile.csproj +++ b/source/#external/Fragile/Fragile/Fragile.csproj @@ -1,6 +1,6 @@ - + - net5.0 + net7.0 enable https://ci.appveyor.com/nuget/vanara-prerelease diff --git a/source/#external/Fragile/Fragile/ProcessRunner.cs b/source/#external/Fragile/Fragile/ProcessRunner.cs index e7f349a0a..5ec130915 100644 --- a/source/#external/Fragile/Fragile/ProcessRunner.cs +++ b/source/#external/Fragile/Fragile/ProcessRunner.cs @@ -16,7 +16,11 @@ namespace Fragile { using SafeAllocatedSID = AdvApi32.SafeAllocatedSID; [SupportedOSPlatform("windows")] - public partial class ProcessRunner : IProcessRunner { + public class ProcessRunner : IProcessRunner { + private static readonly string[] EnvironmentBlock = new[] { + $"LOCALAPPDATA={Environment.GetEnvironmentVariable("LOCALAPPDATA")}" + }; + private readonly ProcessRunnerConfiguration _configuration; private readonly SecurityIdentifier _essentialAccessCapabilityIdentifier; private readonly byte[] _essentialAccessCapabilitySidBytes; @@ -40,7 +44,7 @@ public ProcessRunner(ProcessRunnerConfiguration configuration) { } public void InitialSetup() { - var workingDirectory = new DirectoryInfo(_configuration.WorkingDirectoryPath); + /*var workingDirectory = new DirectoryInfo(_configuration.WorkingDirectoryPath); var workingDirectorySecurity = workingDirectory.GetAccessControl(); workingDirectorySecurity.AddAccessRule(new FileSystemAccessRule( _essentialAccessCapabilityIdentifier, @@ -49,7 +53,7 @@ public void InitialSetup() { PropagationFlags.None, AccessControlType.Allow )); - workingDirectory.SetAccessControl(workingDirectorySecurity); + workingDirectory.SetAccessControl(workingDirectorySecurity);*/ var windowStationHandle = User32.GetProcessWindowStation(); var windowStationSecurity = new WindowObjectSecurity(new WindowObjectNoCloseHandle(windowStationHandle), AccessControlSections.Access); @@ -89,16 +93,18 @@ public IProcessContainer StartProcess() { using var processInformation = CreateProcessInAppContainer(appContainerProfile.sid, streams!.Value); process = Process.GetProcessById(unchecked((int)processInformation.dwProcessId)); + // ensures we can get exit code later + _ = process.Handle; jobObject = AssignProcessToJobObject(processInformation); - ((HRESULT)Kernel32.ResumeThread(processInformation.hThread)).ThrowIfFailed(); + ((HRESULT)Kernel32.ResumeThread(processInformation.hThread)).ThrowIfFailed(); return new ProcessContainer( process, streams!.Value, jobObject, - appContainerProfile.name + appContainerProfile.name ); } catch (Exception ex) { @@ -131,7 +137,7 @@ private static void DisposeLocalClientHandles(StandardStreams? streams) { } private (string name, SafeAllocatedSID sid) CreateAppContainerProfile() { - var name = "fragile-cage-" + Guid.NewGuid().ToString("N"); + var name = "fragile-" + Guid.NewGuid().ToString("N"); UserEnv.CreateAppContainerProfile( name, pszDisplayName: name, @@ -168,7 +174,7 @@ StandardStreams standardStreams standardStreams.Error.ClientSafePipeHandle } ); - + var created = Kernel32.CreateProcess( lpApplicationName: _exeFilePath, lpCommandLine: _commandLine, @@ -178,7 +184,7 @@ StandardStreams standardStreams Kernel32.CREATE_PROCESS.EXTENDED_STARTUPINFO_PRESENT | Kernel32.CREATE_PROCESS.CREATE_SUSPENDED /*| Kernel32.CREATE_PROCESS.DETACHED_PROCESS*/, - null, + lpEnvironment: EnvironmentBlock, lpCurrentDirectory: _configuration.WorkingDirectoryPath, new Kernel32.STARTUPINFOEX { StartupInfo = { diff --git a/source/#external/Mobius.ILasm b/source/#external/Mobius.ILasm index ec1b0f693..bd0ec42e1 160000 --- a/source/#external/Mobius.ILasm +++ b/source/#external/Mobius.ILasm @@ -1 +1 @@ -Subproject commit ec1b0f693e7466016beabbc625bb82a65ce688d7 +Subproject commit bd0ec42e1cc9bb473831abc870fe7ec358e2f42d diff --git a/source/#external/SourcePath b/source/#external/SourcePath index 069e43fb6..43f1548bf 160000 --- a/source/#external/SourcePath +++ b/source/#external/SourcePath @@ -1 +1 @@ -Subproject commit 069e43fb6a426e53ffb1955ffae04bef38c4f83c +Subproject commit 43f1548bff9f0c41206e89a6280c8455f1d3be18 diff --git a/source/#external/mirrorsharp b/source/#external/mirrorsharp index f806da215..b80c9fd5d 160000 --- a/source/#external/mirrorsharp +++ b/source/#external/mirrorsharp @@ -1 +1 @@ -Subproject commit f806da2156fb73f4796c309c388e747ea0d9f3ce +Subproject commit b80c9fd5d7b80b3358a06f9d9a3a5f0c57121d91 diff --git a/source/#external/mirrorsharp-codemirror-6-preview b/source/#external/mirrorsharp-codemirror-6-preview new file mode 160000 index 000000000..037ff9d85 --- /dev/null +++ b/source/#external/mirrorsharp-codemirror-6-preview @@ -0,0 +1 @@ +Subproject commit 037ff9d85fed1b98d6b27fbe2bf42bba55c39be9 diff --git a/source/Container.Manager/Azure/ContainerCountMetricReporter.cs b/source/Container.Manager/Azure/ContainerCountMetricReporter.cs index 4ccf16d2b..e549268e6 100644 --- a/source/Container.Manager/Azure/ContainerCountMetricReporter.cs +++ b/source/Container.Manager/Azure/ContainerCountMetricReporter.cs @@ -8,39 +8,39 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace SharpLab.Container.Manager.Azure { - public class ContainerCountMetricReporter : BackgroundService { - private static readonly string ContainerProcessName = Path.GetFileNameWithoutExtension(Container.Program.ExeFileName); - private static readonly MetricIdentifier ContainerCountMetric = new("Custom Metrics", "Container Count"); +namespace SharpLab.Container.Manager.Azure; - private readonly TelemetryClient _telemetryClient; - private readonly ILogger _logger; +public class ContainerCountMetricReporter : BackgroundService { + private static readonly string ContainerProcessName = Path.GetFileNameWithoutExtension(Container.Program.ExeFileName); + private static readonly MetricIdentifier ContainerCountMetric = new("Custom Metrics", "Container Count"); - public ContainerCountMetricReporter( - TelemetryClient telemetryClient, - ILogger logger - ) { - _telemetryClient = telemetryClient; - _logger = logger; - } + private readonly TelemetryClient _telemetryClient; + private readonly ILogger _logger; - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - while (!stoppingToken.IsCancellationRequested) { - try { - var count = 0; - foreach (var process in Process.GetProcessesByName(ContainerProcessName)) { - count += 1; - process.Dispose(); - } + public ContainerCountMetricReporter( + TelemetryClient telemetryClient, + ILogger logger + ) { + _telemetryClient = telemetryClient; + _logger = logger; + } - _telemetryClient.GetMetric(ContainerCountMetric).TrackValue(count); - } - catch (Exception ex) { - _logger.LogError(ex, "Failed to report container count"); - await Task.Delay(TimeSpan.FromMinutes(4), stoppingToken); + protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + while (!stoppingToken.IsCancellationRequested) { + try { + var count = 0; + foreach (var process in Process.GetProcessesByName(ContainerProcessName)) { + count += 1; + process.Dispose(); } - await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); + + _telemetryClient.GetMetric(ContainerCountMetric).TrackValue(count); + } + catch (Exception ex) { + _logger.LogError(ex, "Failed to report container count"); + await Task.Delay(TimeSpan.FromMinutes(4), stoppingToken); } + await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); } } } diff --git a/source/Container.Manager/Container.Manager.csproj b/source/Container.Manager/Container.Manager.csproj index 0614954dc..963265039 100644 --- a/source/Container.Manager/Container.Manager.csproj +++ b/source/Container.Manager/Container.Manager.csproj @@ -1,7 +1,6 @@ - - net6.0 + net9.0 SharpLab.Container.Manager SharpLab.Container.Manager @@ -14,6 +13,8 @@ + + diff --git a/source/Container.Manager/Endpoints/ExecutionEndpoint.cs b/source/Container.Manager/Endpoints/ExecutionEndpoint.cs index 959cfd696..b29cc1146 100644 --- a/source/Container.Manager/Endpoints/ExecutionEndpoint.cs +++ b/source/Container.Manager/Endpoints/ExecutionEndpoint.cs @@ -36,7 +36,7 @@ public async Task ExecuteAsync(HttpContext context) { var includePerformance = context.Request.Headers["SL-Debug-Performance"].Count > 0; var contentLength = (int)context.Request.Headers.ContentLength!; - _logger.LogDebug("Processing Execute request"); + _logger.LogDebug("Starting Execute"); var stopwatch = includePerformance ? Stopwatch.StartNew() : null; @@ -64,11 +64,11 @@ public async Task ExecuteAsync(HttpContext context) { try { context.Response.StatusCode = 200; - if (!result.IsOutputReadSuccess) - context.Response.Headers.Add("SL-Container-Output-Failed", "true"); + if (!result.IsSuccess) + context.Response.Headers.Append("SL-Container-Output-Failed", "true"); await context.Response.BodyWriter.WriteAsync(result.Output, context.RequestAborted); - if (!result.IsOutputReadSuccess) - await context.Response.BodyWriter.WriteAsync(result.OutputReadFailureMessage, context.RequestAborted); + if (!result.IsSuccess) + await context.Response.BodyWriter.WriteAsync(result.FailureMessage, context.RequestAborted); if (stopwatch != null) { // TODO: Prettify. Put into header? @@ -85,6 +85,7 @@ public async Task ExecuteAsync(HttpContext context) { ArrayPool.Shared.Return(bodyBytes); if (outputBuffer != null) ArrayPool.Shared.Return(outputBuffer); + _logger.LogDebug("Completed Execute"); } } diff --git a/source/Container.Manager/Internal/ActiveContainer.cs b/source/Container.Manager/Internal/ActiveContainer.cs index 0a2e9d7b6..ab5623d58 100644 --- a/source/Container.Manager/Internal/ActiveContainer.cs +++ b/source/Container.Manager/Internal/ActiveContainer.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.IO; using Fragile; @@ -12,12 +11,23 @@ public ActiveContainer( IProcessContainer container ) { _container = container; - CancellableOutputStream = new CancellablePipeStream(container.OutputStream); + CancellableInputStream = new CancellableInputStream(container.InputStream); + CancellableOutputStream = new CancellableOutputStream(container.OutputStream); } - public Stream InputStream => _container.InputStream; + public CancellableInputStream CancellableInputStream { get; private init; } public Stream CancellableOutputStream { get; private init; } - public Process Process => _container.Process; + public int FailureCount { get; set; } + + public bool HasExited() { + try { + return _container.Process.HasExited; + } + // If process has exited a while ago and handle is no longer functional + catch (InvalidOperationException) { + return true; + } + } public void Dispose() => _container.Dispose(); } diff --git a/source/Container.Manager/Internal/CancellableInputStream.cs b/source/Container.Manager/Internal/CancellableInputStream.cs new file mode 100644 index 000000000..b9b695063 --- /dev/null +++ b/source/Container.Manager/Internal/CancellableInputStream.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.IO.Pipes; +using System.Threading; + +namespace SharpLab.Container.Manager.Internal { + public class CancellableInputStream : Stream { + private readonly PipeStream _baseStream; + private bool _cancellationFailed = false; + + public CancellableInputStream(PipeStream baseStream) { + Argument.NotNull(nameof(baseStream), baseStream); + if (!baseStream.CanWrite) + throw new ArgumentException("Stream must be writable.", nameof(baseStream)); + _baseStream = baseStream; + } + + public override void Write(byte[] buffer, int offset, int count) { + if (_cancellationFailed) + throw new InvalidOperationException("Previous stream read cancellation failed, stream is no longer usable."); + if (CancellationToken is not {} cancellationToken) + throw new InvalidOperationException("CancellationToken must be set before calling Write."); + + cancellationToken.ThrowIfCancellationRequested(); + using var cancellationRegistration = cancellationToken.Register(static thisStreamAsObject => { + var thisStream = (CancellableInputStream)thisStreamAsObject!; + if (!NativeMethods.CancelIoEx(thisStream._baseStream.SafePipeHandle, IntPtr.Zero)) + thisStream._cancellationFailed = true; + }, this); + _baseStream.Write(buffer, offset, count); + } + + public CancellationToken? CancellationToken { get; set; } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => throw new NotImplementedException(); + + public override long Position { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void WriteByte(byte value) => throw new NotSupportedException(); + public override void Write(ReadOnlySpan buffer) => throw new NotSupportedException(); + public override void Flush() => throw new NotSupportedException(); + } +} diff --git a/source/Container.Manager/Internal/CancellablePipeStream.cs b/source/Container.Manager/Internal/CancellableOutputStream.cs similarity index 84% rename from source/Container.Manager/Internal/CancellablePipeStream.cs rename to source/Container.Manager/Internal/CancellableOutputStream.cs index e8d3d1554..be8326661 100644 --- a/source/Container.Manager/Internal/CancellablePipeStream.cs +++ b/source/Container.Manager/Internal/CancellableOutputStream.cs @@ -1,64 +1,65 @@ -using System; -using System.IO; -using System.IO.Pipes; -using System.Threading; -using System.Threading.Tasks; - -namespace SharpLab.Container.Manager.Internal { - public class CancellablePipeStream : Stream { - private readonly PipeStream _baseStream; - private bool _cancellationFailed = false; - - public CancellablePipeStream(PipeStream baseStream) { - if (!baseStream.CanRead) - throw new NotSupportedException("CancellablePipeStream only supports readable streams at the moment."); - _baseStream = baseStream; - } - - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (_cancellationFailed) - throw new InvalidOperationException("Previous stream read cancellation failed, stream is no longer usable."); - - cancellationToken.ThrowIfCancellationRequested(); - using var cancellationRegistration = cancellationToken.Register(static thisStreamAsObject => { - var thisStream = (CancellablePipeStream)thisStreamAsObject!; - if (!NativeMethods.CancelIoEx(thisStream._baseStream.SafePipeHandle, IntPtr.Zero)) - thisStream._cancellationFailed = true; - }, this); - return await _baseStream.ReadAsync(buffer, offset, count, cancellationToken); - } - - public override bool CanRead => _baseStream.CanRead; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override long Length => _baseStream.Length; - - public override long Position { - get => _baseStream.Position; - set => throw new NotSupportedException(); - } - - public override void Flush() { - throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) { - throw new NotSupportedException(); - } - - public override long Seek(long offset, SeekOrigin origin) { - throw new NotSupportedException(); - } - - public override void SetLength(long value) { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) { - throw new NotSupportedException(); - } - } -} +using System; +using System.IO; +using System.IO.Pipes; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpLab.Container.Manager.Internal { + public class CancellableOutputStream : Stream { + private readonly PipeStream _baseStream; + private bool _cancellationFailed = false; + + public CancellableOutputStream(PipeStream baseStream) { + Argument.NotNull(nameof(baseStream), baseStream); + if (!baseStream.CanRead) + throw new ArgumentException("Stream must be readable.", nameof(baseStream)); + _baseStream = baseStream; + } + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { + if (_cancellationFailed) + throw new InvalidOperationException("Previous stream read cancellation failed, stream is no longer usable."); + + cancellationToken.ThrowIfCancellationRequested(); + using var cancellationRegistration = cancellationToken.Register(static thisStreamAsObject => { + var thisStream = (CancellableOutputStream)thisStreamAsObject!; + if (!NativeMethods.CancelIoEx(thisStream._baseStream.SafePipeHandle, IntPtr.Zero)) + thisStream._cancellationFailed = true; + }, this); + return await _baseStream.ReadAsync(buffer, offset, count, cancellationToken); + } + + public override bool CanRead => _baseStream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => _baseStream.Length; + + public override long Position { + get => _baseStream.Position; + set => throw new NotSupportedException(); + } + + public override void Flush() { + throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + + public override long Seek(long offset, SeekOrigin origin) { + throw new NotSupportedException(); + } + + public override void SetLength(long value) { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) { + throw new NotSupportedException(); + } + } +} diff --git a/source/Container.Manager/Internal/ContainerAllocationWorker.cs b/source/Container.Manager/Internal/ContainerAllocationWorker.cs index 4c36d9b77..e1e4e90f5 100644 --- a/source/Container.Manager/Internal/ContainerAllocationWorker.cs +++ b/source/Container.Manager/Internal/ContainerAllocationWorker.cs @@ -8,87 +8,87 @@ using Microsoft.Extensions.Logging; using Fragile; -namespace SharpLab.Container.Manager.Internal { - public class ContainerAllocationWorker : BackgroundService { - private readonly ContainerPool _containerPool; - private readonly IProcessRunner _processRunner; - private readonly ExecutionProcessor _warmupExecutionProcessor; - private readonly ContainerCleanupWorker _containerCleanup; - private readonly ILogger _logger; +namespace SharpLab.Container.Manager.Internal; - private readonly byte[] _warmupAssemblyBytes; +public class ContainerAllocationWorker : BackgroundService { + private readonly ContainerPool _containerPool; + private readonly IProcessRunner _processRunner; + private readonly ExecutionProcessor _warmupExecutionProcessor; + private readonly ContainerCleanupWorker _containerCleanup; + private readonly ILogger _logger; - public ContainerAllocationWorker( - ContainerPool containerPool, - IProcessRunner processRunner, - ExecutionProcessor warmupExecutionProcessor, - ContainerCleanupWorker containerCleanup, - ILogger logger - ) { - _containerPool = containerPool; - _processRunner = processRunner; - _warmupExecutionProcessor = warmupExecutionProcessor; - _containerCleanup = containerCleanup; - _logger = logger; + private readonly byte[] _warmupAssemblyBytes; - _warmupAssemblyBytes = File.ReadAllBytes( - Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SharpLab.Container.Warmup.dll") - ); - } + public ContainerAllocationWorker( + ContainerPool containerPool, + IProcessRunner processRunner, + ExecutionProcessor warmupExecutionProcessor, + ContainerCleanupWorker containerCleanup, + ILogger logger + ) { + _containerPool = containerPool; + _processRunner = processRunner; + _warmupExecutionProcessor = warmupExecutionProcessor; + _containerCleanup = containerCleanup; + _logger = logger; + + _warmupAssemblyBytes = File.ReadAllBytes( + Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SharpLab.Container.Warmup.dll") + ); + } - protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - _logger.LogInformation("ContainerAllocationWorker starting"); - _processRunner.InitialSetup(); + protected override async Task ExecuteAsync(CancellationToken stoppingToken) { + _logger.LogInformation("ContainerAllocationWorker starting"); + _processRunner.InitialSetup(); - while (!stoppingToken.IsCancellationRequested) { + while (!stoppingToken.IsCancellationRequested) { + try { + await _containerPool.PreallocatedContainersWriter.WaitToWriteAsync(stoppingToken); + var container = await CreateAndStartContainerAsync(stoppingToken); + await _containerPool.PreallocatedContainersWriter.WriteAsync(container, stoppingToken); + _containerPool.LastContainerPreallocationException = null; + } + catch (Exception ex) { + _containerPool.LastContainerPreallocationException = ex; + _logger.LogError(ex, "Failed to pre-allocate next container, retryng in 1 minute."); try { - await _containerPool.PreallocatedContainersWriter.WaitToWriteAsync(stoppingToken); - var container = await CreateAndStartContainerAsync(stoppingToken); - await _containerPool.PreallocatedContainersWriter.WriteAsync(container, stoppingToken); - _containerPool.LastContainerPreallocationException = null; + await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); } - catch (Exception ex) { - _containerPool.LastContainerPreallocationException = ex; - _logger.LogError(ex, "Failed to pre-allocate next container, retryng in 1 minute."); - try { - await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); - } - catch (TaskCanceledException cancelEx) when (cancelEx.CancellationToken == stoppingToken) { - } + catch (TaskCanceledException cancelEx) when (cancelEx.CancellationToken == stoppingToken) { } } - _containerPool.PreallocatedContainersWriter.Complete(); } + _containerPool.PreallocatedContainersWriter.Complete(); + } - private async Task CreateAndStartContainerAsync(CancellationToken cancellationToken) { - _logger.LogDebug($"Allocating container"); - - var processContainer = _processRunner.StartProcess(); - try { - var activeContainer = new ActiveContainer(processContainer); - - var outputBuffer = ArrayPool.Shared.Rent(2048); - try { - var result = await _warmupExecutionProcessor.ExecuteInContainerAsync( - activeContainer, _warmupAssemblyBytes, outputBuffer, - includePerformance: false, isWarmup: true, - cancellationToken - ); - if (!result.IsOutputReadSuccess) - throw new Exception($"Warmup output failed:\r\n" + Encoding.UTF8.GetString(result.Output.Span) + Encoding.UTF8.GetString(result.OutputReadFailureMessage.Span)); - } - finally { - ArrayPool.Shared.Return(outputBuffer); - } + private async Task CreateAndStartContainerAsync(CancellationToken cancellationToken) { + _logger.LogDebug($"Allocating container"); - _logger.LogDebug("Allocated container"); + var processContainer = _processRunner.StartProcess(); + try { + var activeContainer = new ActiveContainer(processContainer); - return activeContainer; + var outputBuffer = ArrayPool.Shared.Rent(2048); + try { + var result = await _warmupExecutionProcessor.ExecuteInContainerAsync( + activeContainer, _warmupAssemblyBytes, outputBuffer, + includePerformance: false, isWarmup: true, + cancellationToken + ); + if (!result.IsSuccess) + throw new Exception($"Warmup failed:\r\n" + Encoding.UTF8.GetString(result.Output.Span) + Encoding.UTF8.GetString(result.FailureMessage.Span)); } - catch { - _containerCleanup.QueueForCleanup(processContainer); - throw; + finally { + ArrayPool.Shared.Return(outputBuffer); } + + _logger.LogDebug("Allocated container"); + + return activeContainer; + } + catch { + _containerCleanup.QueueForCleanup(processContainer); + throw; } } } diff --git a/source/Container.Manager/Internal/CrashSuspensionManager.cs b/source/Container.Manager/Internal/CrashSuspensionManager.cs index 7d8ed5895..7474a4483 100644 --- a/source/Container.Manager/Internal/CrashSuspensionManager.cs +++ b/source/Container.Manager/Internal/CrashSuspensionManager.cs @@ -1,3 +1,4 @@ +using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; using System.Linq; @@ -7,10 +8,15 @@ namespace SharpLab.Container.Manager.Internal { public class CrashSuspensionManager { private const int InitialSuspensionSeconds = 15; private static readonly byte[][] SuspensionMessages = Enumerable.Range(0, InitialSuspensionSeconds + 1) - .Select(s => Encoding.UTF8.GetBytes($"(Container crashed, next container will be available in {s} second{(s != 1 ? "s" : "")})")) + .Select(s => Encoding.UTF8.GetBytes($"(Container crashed or timed out. Next container will be available in {s} second{(s != 1 ? "s" : "")})")) .ToArray(); private readonly ConcurrentDictionary _suspensions = new(); + private readonly ILogger _logger; + + public CrashSuspensionManager(ILogger logger) { + _logger = logger; + } public ExecutionOutputResult? GetSuspension(string sessionId) { if (!_suspensions.TryGetValue(sessionId, out var suspensionEndTime)) @@ -19,10 +25,12 @@ public class CrashSuspensionManager { var secondsLeft = Math.Min((int)(suspensionEndTime - DateTime.Now).TotalSeconds, InitialSuspensionSeconds); if (secondsLeft <= 0) { _suspensions.TryRemove(sessionId, out _); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("Removing suspension for session {sessionId}", sessionId); return null; } - return new(ReadOnlyMemory.Empty, SuspensionMessages[secondsLeft]); + return ExecutionOutputResult.Failure(SuspensionMessages[secondsLeft]); } public ExecutionOutputResult SetSuspension(string sessionId, ExecutionOutputResult result) { @@ -30,7 +38,9 @@ public ExecutionOutputResult SetSuspension(string sessionId, ExecutionOutputResu if (!_suspensions.TryAdd(sessionId, endTime)) throw new Exception($"Concurrency conflict when trying to add suspension for session id {sessionId}"); - return new(result.Output, SuspensionMessages[InitialSuspensionSeconds]); + if (_logger.IsEnabled(LogLevel.Debug)) + _logger.LogDebug("Adding suspension for session {sessionId}", sessionId); + return ExecutionOutputResult.Failure(SuspensionMessages[InitialSuspensionSeconds], result.Output); } } } diff --git a/source/Container.Manager/Internal/ExecutionManager.cs b/source/Container.Manager/Internal/ExecutionManager.cs index 9858ddd53..ed42edc62 100644 --- a/source/Container.Manager/Internal/ExecutionManager.cs +++ b/source/Container.Manager/Internal/ExecutionManager.cs @@ -34,7 +34,6 @@ CancellationToken cancellationToken if (_containerPool.GetSessionContainer(sessionId) is not {} container) { if (_crashSuspensionManager.GetSuspension(sessionId) is {} suspension) return suspension; - try { container = await _containerPool.AllocateSessionContainerAsync(sessionId, _cleanupWorker.QueueForCleanup, allocationCancellation.Token); } @@ -52,13 +51,24 @@ CancellationToken cancellationToken cancellationToken ); - if (!result.IsOutputReadSuccess) { - if (container.Process.HasExited) - _containerPool.RemoveSessionContainer(sessionId); + if (container.HasExited()) + return RemoveContainerAndSetSuspension(sessionId, result); - return _crashSuspensionManager.SetSuspension(sessionId, result); + if (result.IsSuccess) { + container.FailureCount = 0; + } + else { + container.FailureCount += 1; + if (container.FailureCount >= 3) + return RemoveContainerAndSetSuspension(sessionId, result); } + return result; } + + private ExecutionOutputResult RemoveContainerAndSetSuspension(string sessionId, ExecutionOutputResult result) { + _containerPool.RemoveSessionContainer(sessionId); + return _crashSuspensionManager.SetSuspension(sessionId, result); + } } } \ No newline at end of file diff --git a/source/Container.Manager/Internal/ExecutionOutputResult.cs b/source/Container.Manager/Internal/ExecutionOutputResult.cs index 0b5c16958..d56a612bb 100644 --- a/source/Container.Manager/Internal/ExecutionOutputResult.cs +++ b/source/Container.Manager/Internal/ExecutionOutputResult.cs @@ -2,18 +2,19 @@ namespace SharpLab.Container.Manager.Internal { public readonly struct ExecutionOutputResult { - public ExecutionOutputResult(ReadOnlyMemory output) { - Output = output; - OutputReadFailureMessage = default; + private static class Messages { } - public ExecutionOutputResult(ReadOnlyMemory output, ReadOnlyMemory outputReadFailureMessage) { + private ExecutionOutputResult(ReadOnlyMemory output, ReadOnlyMemory failureMessage) { Output = output; - OutputReadFailureMessage = outputReadFailureMessage; + FailureMessage = failureMessage; } + public static ExecutionOutputResult Success(ReadOnlyMemory output) => new(output, default); + public static ExecutionOutputResult Failure(ReadOnlyMemory failureMessage, ReadOnlyMemory output = default) => new(output, failureMessage); + public ReadOnlyMemory Output { get; } - public ReadOnlyMemory OutputReadFailureMessage { get; } - public bool IsOutputReadSuccess => OutputReadFailureMessage.IsEmpty; + public ReadOnlyMemory FailureMessage { get; } + public bool IsSuccess => FailureMessage.IsEmpty; } } diff --git a/source/Container.Manager/Internal/ExecutionProcessor.cs b/source/Container.Manager/Internal/ExecutionProcessor.cs index 97d795dad..92a77b5ce 100644 --- a/source/Container.Manager/Internal/ExecutionProcessor.cs +++ b/source/Container.Manager/Internal/ExecutionProcessor.cs @@ -3,16 +3,19 @@ using System.Buffers.Text; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.Logging; using SharpLab.Container.Protocol.Stdin; namespace SharpLab.Container.Manager.Internal { public class ExecutionProcessor { private readonly StdinWriter _stdinWriter; private readonly StdoutReader _stdoutReader; + private readonly ILogger _logger; - public ExecutionProcessor(StdinWriter stdinWriter, StdoutReader stdoutReader) { + public ExecutionProcessor(StdinWriter stdinWriter, StdoutReader stdoutReader, ILogger logger) { _stdinWriter = stdinWriter; _stdoutReader = stdoutReader; + _logger = logger; } public async Task ExecuteInContainerAsync( @@ -25,12 +28,15 @@ CancellationToken cancellationToken ) { var outputStartMarker = Guid.NewGuid(); var outputEndMarker = Guid.NewGuid(); - _stdinWriter.WriteCommand(container.InputStream, new ExecuteCommand( + + var writeResult = _stdinWriter.WriteCommand(container.CancellableInputStream, new ExecuteCommand( assemblyBytes, outputStartMarker, outputEndMarker, includePerformance - )); + ), cancellationToken); + if (!writeResult.IsSuccess) + return ExecutionOutputResult.Failure(writeResult.FailureMessage); const int OutputMarkerLength = 36; // length of guid byte[]? outputStartMarkerBytes = null; diff --git a/source/Container.Manager/Internal/FailureMessages.cs b/source/Container.Manager/Internal/FailureMessages.cs new file mode 100644 index 000000000..9b9588000 --- /dev/null +++ b/source/Container.Manager/Internal/FailureMessages.cs @@ -0,0 +1,9 @@ +using System.Text; +using System; + +namespace SharpLab.Container.Manager.Internal { + public static class FailureMessages { + public static readonly ReadOnlyMemory TimedOut = Encoding.UTF8.GetBytes("\n(Execution timed out)"); + public static readonly ReadOnlyMemory IOFailure = Encoding.UTF8.GetBytes("\n(Unexpected IO failure)"); + } +} diff --git a/source/Container.Manager/Internal/StdinWriter.cs b/source/Container.Manager/Internal/StdinWriter.cs index 3189bee2f..8746316f5 100644 --- a/source/Container.Manager/Internal/StdinWriter.cs +++ b/source/Container.Manager/Internal/StdinWriter.cs @@ -1,11 +1,36 @@ +using System; using System.IO; +using System.Threading; +using Microsoft.Extensions.Logging; using ProtoBuf; using SharpLab.Container.Protocol.Stdin; namespace SharpLab.Container.Manager.Internal { public class StdinWriter { - public void WriteCommand(Stream stream, StdinCommand command) { - Serializer.SerializeWithLengthPrefix(stream, command, PrefixStyle.Base128); + private readonly ILogger _logger; + + public StdinWriter(ILogger logger) { + _logger = logger; + } + + public StdinWriterResult WriteCommand(CancellableInputStream stream, StdinCommand command, CancellationToken cancellationToken) { + // Safe operation -- stream is associated with the container and is only vailable to one request at once + stream.CancellationToken = cancellationToken; + try { + Serializer.SerializeWithLengthPrefix(stream, command, PrefixStyle.Base128); + return StdinWriterResult.Success; + } + catch (IOException ex) { + _logger.LogInformation(ex, "Failed to write stream"); + return StdinWriterResult.Failure(FailureMessages.IOFailure); + } + catch (OperationCanceledException) { + _logger.LogDebug("Timed out while writing stream"); + return StdinWriterResult.Failure(FailureMessages.TimedOut); + } + finally { + stream.CancellationToken = null; + } } } } diff --git a/source/Container.Manager/Internal/StdinWriterResult.cs b/source/Container.Manager/Internal/StdinWriterResult.cs new file mode 100644 index 000000000..2309b87ee --- /dev/null +++ b/source/Container.Manager/Internal/StdinWriterResult.cs @@ -0,0 +1,16 @@ +using System; + +namespace SharpLab.Container.Manager.Internal { + public readonly struct StdinWriterResult { + private StdinWriterResult(bool isSuccess, ReadOnlyMemory failureMessage) { + IsSuccess = isSuccess; + FailureMessage = failureMessage; + } + + public static StdinWriterResult Success { get; } = new (true, ReadOnlyMemory.Empty); + public static StdinWriterResult Failure(ReadOnlyMemory message) => new (false, message); + + public bool IsSuccess { get; } + public ReadOnlyMemory FailureMessage { get; } + } +} diff --git a/source/Container.Manager/Internal/StdoutReader.cs b/source/Container.Manager/Internal/StdoutReader.cs index 4e7609deb..2f9a21817 100644 --- a/source/Container.Manager/Internal/StdoutReader.cs +++ b/source/Container.Manager/Internal/StdoutReader.cs @@ -7,7 +7,6 @@ namespace SharpLab.Container.Manager.Internal { public class StdoutReader { - private static readonly byte[] ExecutionTimedOut = Encoding.UTF8.GetBytes("\n(Execution timed out)"); private static readonly byte[] StartOfOutputNotFound = Encoding.UTF8.GetBytes("\n(Could not find start of output)"); private static readonly byte[] UnexpectedEndOfOutput = Encoding.UTF8.GetBytes("\n(Unexpected end of output)"); private readonly ILogger _logger; @@ -28,16 +27,21 @@ CancellationToken cancellationToken var outputEndIndex = -1; var nextStartMarkerIndexToCompare = 0; var nextEndMarkerIndexToCompare = 0; - var cancelled = false; + var exceptionFailureMessage = ReadOnlyMemory.Empty; while (outputEndIndex < 0) { int readCount; try { readCount = await stream.ReadAsync(outputBuffer, currentIndex, outputBuffer.Length - currentIndex, cancellationToken); } + catch (IOException ex) { + exceptionFailureMessage = FailureMessages.IOFailure; + _logger.LogInformation(ex, "Failed to read stream"); + break; + } catch (OperationCanceledException) { - cancelled = true; - _logger.LogDebug("Timeout at stream.ReadAsync"); + exceptionFailureMessage = FailureMessages.TimedOut; + _logger.LogDebug("Timed out while reading stream"); break; } @@ -46,7 +50,7 @@ CancellationToken cancellationToken await Task.Delay(10, cancellationToken); } catch (OperationCanceledException) { - cancelled = true; + exceptionFailureMessage = FailureMessages.TimedOut; break; } continue; @@ -77,13 +81,13 @@ CancellationToken cancellationToken } if (outputStartIndex < 0) - return new(outputBuffer.AsMemory(0, currentIndex), StartOfOutputNotFound); - if (cancelled) - return new(outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex), ExecutionTimedOut); + return ExecutionOutputResult.Failure(StartOfOutputNotFound, outputBuffer.AsMemory(0, currentIndex)); + if (!exceptionFailureMessage.IsEmpty) + return ExecutionOutputResult.Failure(exceptionFailureMessage, outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex)); if (outputEndIndex < 0) - return new(outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex), UnexpectedEndOfOutput); + return ExecutionOutputResult.Failure(UnexpectedEndOfOutput, outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex)); - return new(outputBuffer.AsMemory(outputStartIndex, outputEndIndex - outputStartIndex)); + return ExecutionOutputResult.Success(outputBuffer.AsMemory(outputStartIndex, outputEndIndex - outputStartIndex)); } private static int GetMarkerEndIndex(byte[] outputBuffer, int currentIndex, int length, ReadOnlyMemory marker, ref int nextMarkerIndexToCompare) { diff --git a/source/Container.Manager/Startup.cs b/source/Container.Manager/Startup.cs index 016593f80..66a0b8906 100644 --- a/source/Container.Manager/Startup.cs +++ b/source/Container.Manager/Startup.cs @@ -9,67 +9,67 @@ using SharpLab.Container.Manager.Endpoints; using SharpLab.Container.Manager.Internal; -namespace SharpLab.Container.Manager { - [SupportedOSPlatform("windows")] - public class Startup { - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 +namespace SharpLab.Container.Manager; - public void ConfigureServices(IServiceCollection services) - { - // TODO: proper DI, e.g. Autofac - services.AddSingleton(new ProcessRunnerConfiguration( - workingDirectoryPath: AppContext.BaseDirectory, - exeFileName: Container.Program.ExeFileName, - essentialAccessCapabilitySid: "S-1-15-3-1024-4233803318-1181731508-1220533431-3050556506-2713139869-1168708946-594703785-1824610955", - maximumMemorySize: 30 * 1024 * 1024, - maximumCpuPercentage: 1 - )); - services.AddSingleton(); - services.AddSingleton(); +[SupportedOSPlatform("windows")] +public class Startup { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - services.AddSingleton(); + public void ConfigureServices(IServiceCollection services) + { + // TODO: proper DI, e.g. Autofac + services.AddSingleton(new ProcessRunnerConfiguration( + workingDirectoryPath: AppContext.BaseDirectory, + exeFileName: Container.Program.ExeFileName, + essentialAccessCapabilitySid: "S-1-15-3-1024-4233803318-1181731508-1220533431-3050556506-2713139869-1168708946-594703785-1824610955", + maximumMemorySize: 30 * 1024 * 1024, + maximumCpuPercentage: 1 + )); + services.AddSingleton(); + services.AddSingleton(); - var authorizationToken = Environment.GetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN") - ?? throw new Exception("Required environment variable SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN was not provided."); - services.AddSingleton(new ExecutionEndpointSettings(authorizationToken)); - services.AddSingleton(); + services.AddSingleton(); - services.AddSingleton(); + var authorizationToken = Environment.GetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN") + ?? throw new Exception("Required environment variable SHARPLAB_CONTAINER_HOST_AUTHORIZATION_TOKEN was not provided."); + services.AddSingleton(new ExecutionEndpointSettings(authorizationToken)); + services.AddSingleton(); - services.AddHostedService(); - services.AddSingleton(); - services.AddHostedService(c => c.GetRequiredService()); + services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddHostedService(); + services.AddSingleton(); + services.AddHostedService(c => c.GetRequiredService()); - ConfigureAzureDependentServices(services); - } + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); - private void ConfigureAzureDependentServices(IServiceCollection services) { - var instrumentationKey = Environment.GetEnvironmentVariable("SHARPLAB_TELEMETRY_KEY"); - if (instrumentationKey == null) { - Console.WriteLine("[WARN] AppInsights instrumentation key was not found."); - return; - } + ConfigureAzureDependentServices(services); + } - var configuration = new TelemetryConfiguration { InstrumentationKey = instrumentationKey }; - services.AddSingleton(new TelemetryClient(configuration)); - services.AddHostedService(); + private void ConfigureAzureDependentServices(IServiceCollection services) { + var connectionString = Environment.GetEnvironmentVariable("SHARPLAB_TELEMETRY_CONNECTION_STRING"); + if (connectionString == null) { + Console.WriteLine("[WARN] AppInsights connection string was not found."); + return; } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app) { - app.UseRouting(); + var configuration = new TelemetryConfiguration { ConnectionString = connectionString }; + services.AddSingleton(new TelemetryClient(configuration)); + services.AddHostedService(); + } - app.UseEndpoints(endpoints => { - endpoints.MapGet("/status", app.ApplicationServices.GetRequiredService().ExecuteAsync); - endpoints.MapPost("/", app.ApplicationServices.GetRequiredService().ExecuteAsync); - }); - } + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) { + app.UseRouting(); + + app.UseEndpoints(endpoints => { + endpoints.MapGet("/status", app.ApplicationServices.GetRequiredService().ExecuteAsync); + endpoints.MapPost("/", app.ApplicationServices.GetRequiredService().ExecuteAsync); + }); } } diff --git a/source/Container.Warmup/Container.Warmup.csproj b/source/Container.Warmup/Container.Warmup.csproj index 3091f1ac6..bf027354b 100644 --- a/source/Container.Warmup/Container.Warmup.csproj +++ b/source/Container.Warmup/Container.Warmup.csproj @@ -1,7 +1,7 @@ Exe - net6.0 + net9.0 SharpLab.Container.Warmup SharpLab.Container.Warmup diff --git a/source/Container/Container.csproj b/source/Container/Container.csproj index d56a6d795..e3c02ea44 100644 --- a/source/Container/Container.csproj +++ b/source/Container/Container.csproj @@ -1,6 +1,6 @@ - net6.0 + net9.0 SharpLab.Container SharpLab.Container Exe @@ -8,8 +8,8 @@ - - + + diff --git a/source/Container/Execution/ExecuteCommandHandler.cs b/source/Container/Execution/ExecuteCommandHandler.cs index 6dc61b894..3b171dd4e 100644 --- a/source/Container/Execution/ExecuteCommandHandler.cs +++ b/source/Container/Execution/ExecuteCommandHandler.cs @@ -37,7 +37,7 @@ public void Execute(ExecuteCommand command) { ? inner : ex; Output.Write(new SimpleInspection("Exception", exceptionToReport.ToString())); - ContainerFlow.ReportException(exceptionToReport); + Flow.ReportException(exceptionToReport); _flowWriter.FlushAndReset(); } catch { diff --git a/source/Container/Runtime/FlowWriter.cs b/source/Container/Runtime/FlowWriter.cs index bdaa5e6fd..419e3f3cf 100644 --- a/source/Container/Runtime/FlowWriter.cs +++ b/source/Container/Runtime/FlowWriter.cs @@ -9,9 +9,8 @@ namespace SharpLab.Container.Runtime { internal partial class FlowWriter : IFlowWriter { private static class Limits { - public const int MaxRecords = 50; - public const int MaxValuesPerLine = 3; - public const int MaxNameLength = 10; + public const int MaxRecords = 200; + public const int MaxNameLength = 20; public static readonly ValuePresenterLimits Value = new(maxValueLength: 10, maxEnumerableItemCount: 3); } @@ -19,8 +18,7 @@ private static class Limits { private readonly StdoutWriter _stdoutWriter; private readonly Utf8ValuePresenter _valuePresenter; private readonly byte[] _truncatedNameBytes = new byte[(Limits.MaxNameLength - 1) + Utf8Ellipsis.Length]; - private readonly FlowRecord[] _records = new FlowRecord[50]; - private readonly int[] _valueCountsPerLine = new int[75]; + private readonly FlowRecord[] _records = new FlowRecord[Limits.MaxRecords]; private int _currentRecordIndex = -1; public FlowWriter( @@ -31,6 +29,11 @@ Utf8ValuePresenter valuePresenter _valuePresenter = valuePresenter; } + // Must be thread safe + public void WriteArea(FlowAreaKind kind, int startLineNumber, int endLineNumber) { + TryAddRecord(new (kind, startLineNumber, endLineNumber)); + } + // Must be thread safe public void WriteLineVisit(int lineNumber) { TryAddRecord(new (lineNumber)); @@ -38,16 +41,6 @@ public void WriteLineVisit(int lineNumber) { // Must be thread safe public void WriteValue(T value, string? name, int lineNumber) { - if (lineNumber >= _valueCountsPerLine.Length || _valueCountsPerLine[lineNumber] > Limits.MaxValuesPerLine) - return; - - var valueCountPerLine = Interlocked.Increment(ref _valueCountsPerLine[lineNumber]); - if (valueCountPerLine > Limits.MaxValuesPerLine) { - if (valueCountPerLine == Limits.MaxValuesPerLine + 1) - TryAddRecord(new(lineNumber, null, VariantValue.From("…"))); - return; - } - TryAddRecord(new (lineNumber, name, VariantValue.From(value))); } @@ -56,6 +49,11 @@ public void WriteSpanValue(ReadOnlySpan value, string? name, int lineNumbe // TODO (can't store this, have to actually write it) } + // Must be thread safe + public void WriteTag(FlowRecordTag tag) { + TryAddRecord(new (tag)); + } + // Must be thread safe public void WriteException(object exception) { TryAddRecord(new (exception)); @@ -79,7 +77,6 @@ public void FlushAndReset() { var recordCount = Math.Min(_currentRecordIndex + 1, _records.Length); _currentRecordIndex = -1; - Array.Clear(_valueCountsPerLine, 0, _valueCountsPerLine.Length); if (recordCount == 0) return; @@ -100,6 +97,30 @@ private void WriteRecordToWriter(Utf8JsonWriter writer, FlowRecord record) { return; } + if (record.AreaKind is {} area) { + writer.WriteStartArray(); + writer.WriteStringValue(record.AreaKind switch { + FlowAreaKind.Method => MethodAreaCode, + FlowAreaKind.Loop => LoopAreaCode, + var u => throw new NotSupportedException("Unknown flow area kind: " + u.ToString()) + }); + writer.WriteNumberValue(record.StartLineNumber); + writer.WriteNumberValue(record.EndLineNumber); + writer.WriteEndArray(); + return; + } + + if (record.Tag is {} tag) { + var code = tag switch { + FlowRecordTag.LoopStart => LoopStartCode, + FlowRecordTag.LoopEnd => LoopEndCode, + FlowRecordTag.Jump => JumpCode, + _ => throw new NotSupportedException("Unknown flow tag: " + tag.ToString()) + }; + writer.WriteStringValue(code); + return; + } + if (record.Exception is {} exception) { writer.WriteStartObject(); writer.WriteString(Exception, record.Exception.GetType().Name); @@ -162,25 +183,48 @@ public FlowRecord(int lineNumber, string? name, VariantValue value) { Name = name; Value = value; Exception = default; + Tag = default; + AreaKind = default; + EndLineNumber = default; + } + + public FlowRecord(FlowRecordTag tag) : this() { + Tag = tag; } public FlowRecord(object exception) : this() { Exception = exception; } + public FlowRecord(FlowAreaKind areaKind, int startLineNumber, int endLineNumber) : this() { + AreaKind = areaKind; + LineNumber = startLineNumber; + EndLineNumber = endLineNumber; + } public int LineNumber { get; } public string? Name { get; } public VariantValue? Value { get; } + public FlowRecordTag? Tag { get; } public object? Exception { get; } + public FlowAreaKind? AreaKind { get; } + public int StartLineNumber => LineNumber; + public int EndLineNumber { get; } + // allocates -- debug only public override string ToString() { if (Exception != null) return "{exception: " + Exception.GetType().Name + "}"; + if (Tag != null) + return "{tag: " + Tag + "}"; + if (Value != null) return "{value}"; + if (AreaKind != null) + return "{area: " + AreaKind + ", start: " + StartLineNumber + ", end: " + EndLineNumber + "}"; + return "{line: " + LineNumber + "}"; } } diff --git a/source/Container/Runtime/JsonStrings.cs b/source/Container/Runtime/JsonStrings.cs index e6930dfee..2c1de764b 100644 --- a/source/Container/Runtime/JsonStrings.cs +++ b/source/Container/Runtime/JsonStrings.cs @@ -29,6 +29,11 @@ internal static class JsonStrings { // Flow public static readonly JsonEncodedText Flow = Encode("flow"); public static readonly JsonEncodedText Exception = Encode("exception"); + public static readonly JsonEncodedText MethodAreaCode = Encode("m"); + public static readonly JsonEncodedText LoopAreaCode = Encode("l"); + public static readonly JsonEncodedText JumpCode = Encode("j"); + public static readonly JsonEncodedText LoopStartCode = Encode("ls"); + public static readonly JsonEncodedText LoopEndCode = Encode("le"); private static JsonEncodedText Encode(string text) => JsonEncodedText.Encode(text, JavaScriptEncoder.UnsafeRelaxedJsonEscaping); diff --git a/source/Container/Runtime/MemoryBytesInspector.cs b/source/Container/Runtime/MemoryBytesInspector.cs index f5859bcb4..2e8c58796 100644 --- a/source/Container/Runtime/MemoryBytesInspector.cs +++ b/source/Container/Runtime/MemoryBytesInspector.cs @@ -4,133 +4,133 @@ using Microsoft.Diagnostics.Runtime; using SharpLab.Runtime.Internal; -namespace SharpLab.Container.Runtime { - internal class MemoryBytesInspector : IMemoryBytesInspector { - private readonly Pool _runtimePool; +namespace SharpLab.Container.Runtime; - public MemoryBytesInspector(Pool runtimePool) { - _runtimePool = runtimePool; - } +internal class MemoryBytesInspector : IMemoryBytesInspector { + private readonly Pool _runtimePool; - public MemoryInspection InspectHeap(object @object) { - if (@object == null) - throw new ArgumentNullException(nameof(@object), $"Inspect.Heap can't inspect null, as it does not point to a valid location on the heap."); + public MemoryBytesInspector(Pool runtimePool) { + _runtimePool = runtimePool; + } - using var runtimeLease = _runtimePool.GetOrCreate(); - var runtime = runtimeLease.Object; - runtime.FlushCachedData(); + public MemoryInspection InspectHeap(object @object) { + if (@object == null) + throw new ArgumentNullException(nameof(@object), $"Inspect.Heap can't inspect null, as it does not point to a valid location on the heap."); - var address = (ulong)GetHeapPointer(@object); - var objectType = runtime.Heap.GetObjectType(address); - if (objectType == null) - throw new ClrInformationNotFoundException($"Failed to find object type for address 0x{address:X}."); + using var runtimeLease = _runtimePool.GetOrCreate(); + var runtime = runtimeLease.Object; + runtime.FlushCachedData(); - var objectSize = runtime.Heap.GetObjectSize(address, objectType); + var address = (ulong)GetHeapPointer(@object); + var objectType = runtime.Heap.GetObjectType(address); + if (objectType == null) + throw new ClrInformationNotFoundException($"Failed to find object type for address 0x{address:X}."); - // Move by one pointer size back -- Object Header, - // see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/ - // - // Not sure if there is a better way to get this through ClrMD yet. - // https://github.com/Microsoft/clrmd/issues/99 - var objectStart = address - (uint)IntPtr.Size; - var data = ReadMemory(runtime, objectStart, objectSize); + var objectSize = runtime.Heap.GetObject(address, objectType).Size; - var labels = CreateLabelsFromType(objectType, address, objectStart, first: (index: 2, offset: 2 * IntPtr.Size)); - labels[0] = new MemoryInspectionLabel("header", 0, IntPtr.Size); - labels[1] = new MemoryInspectionLabel("type handle", IntPtr.Size, IntPtr.Size); + // Move by one pointer size back -- Object Header, + // see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/ + // + // Not sure if there is a better way to get this through ClrMD yet. + // https://github.com/Microsoft/clrmd/issues/99 + var objectStart = address - (uint)IntPtr.Size; + var data = ReadMemory(runtime, objectStart, objectSize); - return new MemoryInspection($"{objectType.Name} at 0x{address:X}", labels, data); - } + var labels = CreateLabelsFromType(objectType, address, objectStart, first: (index: 2, offset: 2 * IntPtr.Size)); + labels[0] = new MemoryInspectionLabel("header", 0, IntPtr.Size); + labels[1] = new MemoryInspectionLabel("type handle", IntPtr.Size, IntPtr.Size); - public unsafe MemoryInspection InspectStack(in T value) { - using var runtimeLease = _runtimePool.GetOrCreate(); - var runtime = runtimeLease.Object; + return new MemoryInspection($"{objectType.Name} at 0x{address:X}", labels, data); + } - var type = typeof(T); + public unsafe MemoryInspection InspectStack(in T value) { + using var runtimeLease = _runtimePool.GetOrCreate(); + var runtime = runtimeLease.Object; - var address = (ulong)Unsafe.AsPointer(ref Unsafe.AsRef(in value)); - var size = type.IsValueType ? (ulong)Unsafe.SizeOf() : (uint)IntPtr.Size; - var data = ReadMemory(runtime, address, size); + var type = typeof(T); - MemoryInspectionLabel[] labels; - if (type.IsValueType && !type.IsPrimitive) { - runtime.FlushCachedData(); - var methodTableAddress = (ulong)type.TypeHandle.Value; - var runtimeType = runtime.GetTypeByMethodTable(methodTableAddress) - ?? throw new ClrInformationNotFoundException($"Could not find type by method table at 0x{methodTableAddress:X}"); - labels = CreateLabelsFromType(runtimeType, address, address + (uint)IntPtr.Size); - } - else { - labels = Array.Empty(); - } - - var title = type.IsValueType - ? $"{type.FullName}" - : $"Pointer to {type.FullName}"; + var address = (ulong)Unsafe.AsPointer(ref Unsafe.AsRef(in value)); + var size = type.IsValueType ? (ulong)Unsafe.SizeOf() : (uint)IntPtr.Size; + var data = ReadMemory(runtime, address, size); - return new MemoryInspection(title, labels, data); + MemoryInspectionLabel[] labels; + if (type.IsValueType && !type.IsPrimitive) { + runtime.FlushCachedData(); + var methodTableAddress = (ulong)type.TypeHandle.Value; + var runtimeType = runtime.GetTypeByMethodTable(methodTableAddress) + ?? throw new ClrInformationNotFoundException($"Could not find type by method table at 0x{methodTableAddress:X}"); + labels = CreateLabelsFromType(runtimeType, address, address + (uint)IntPtr.Size); } - - private static byte[] ReadMemory(ClrRuntime runtime, ulong address, ulong size) { - var data = new byte[size]; - runtime.DataTarget!.DataReader.Read(address, data); - return data; + else { + labels = Array.Empty(); } - private MemoryInspectionLabel[] CreateLabelsFromType( - ClrType objectType, - ulong objectAddress, - ulong offsetBase, - (int index, int offset) first = default - ) { - MemoryInspectionLabel[] labels; - if (objectType.IsArray) { - var length = objectType.Heap.GetObject(objectAddress).AsArray().Length; - labels = new MemoryInspectionLabel[first.index + 1 + length]; - labels[first.index] = new MemoryInspectionLabel("length", first.offset, IntPtr.Size); - for (var i = 0; i < length; i++) { - var elementAddress = objectType.GetArrayElementAddress(objectAddress, i); - var offset = (int)(elementAddress - offsetBase); - labels[first.index + 1 + i] = new MemoryInspectionLabel( - i.ToString(), - offset, - objectType.ComponentSize, - GetNestedLabels(objectType.ComponentType!, elementAddress, offsetBase) - ); - } - return labels; - } + var title = type.IsValueType + ? $"{type.FullName}" + : $"Pointer to {type.FullName}"; - var fields = objectType.Fields; - var fieldCount = fields.Length; - labels = new MemoryInspectionLabel[first.index + fieldCount]; - for (var i = 0; i < fieldCount; i++) { - var field = fields[i]; - if (field.Type == null) - throw new ClrInformationNotFoundException($"Could not get type for field {field.Name}."); - - var fieldAddress = field.GetAddress(objectAddress); - var offset = (int)(fieldAddress - offsetBase); - labels[first.index + i] = new MemoryInspectionLabel( - field.Name ?? "", + return new MemoryInspection(title, labels, data); + } + + private static byte[] ReadMemory(ClrRuntime runtime, ulong address, ulong size) { + var data = new byte[size]; + runtime.DataTarget!.DataReader.Read(address, data); + return data; + } + + private MemoryInspectionLabel[] CreateLabelsFromType( + ClrType objectType, + ulong objectAddress, + ulong offsetBase, + (int index, int offset) first = default + ) { + MemoryInspectionLabel[] labels; + if (objectType.IsArray) { + var length = objectType.Heap.GetObject(objectAddress).AsArray().Length; + labels = new MemoryInspectionLabel[first.index + 1 + length]; + labels[first.index] = new MemoryInspectionLabel("length", first.offset, IntPtr.Size); + for (var i = 0; i < length; i++) { + var elementAddress = objectType.GetArrayElementAddress(objectAddress, i); + var offset = (int)(elementAddress - offsetBase); + labels[first.index + 1 + i] = new MemoryInspectionLabel( + i.ToString(), offset, - field.Size, - GetNestedLabels(field.Type, fieldAddress, offsetBase) + objectType.ComponentSize, + GetNestedLabels(objectType.ComponentType!, elementAddress, offsetBase) ); } return labels; } - private IReadOnlyList GetNestedLabels(ClrType type, ulong valueAddress, ulong offsetBase) { - if (type.IsPrimitive || !type.IsValueType) - return Array.Empty(); - - return CreateLabelsFromType(type, valueAddress, offsetBase + (uint)IntPtr.Size); + var fields = objectType.Fields; + var fieldCount = fields.Length; + labels = new MemoryInspectionLabel[first.index + fieldCount]; + for (var i = 0; i < fieldCount; i++) { + var field = fields[i]; + if (field.Type == null) + throw new ClrInformationNotFoundException($"Could not get type for field {field.Name}."); + + var fieldAddress = field.GetAddress(objectAddress); + var offset = (int)(fieldAddress - offsetBase); + labels[first.index + i] = new MemoryInspectionLabel( + field.Name ?? "", + offset, + field.Size, + GetNestedLabels(field.Type, fieldAddress, offsetBase) + ); } + return labels; + } - private static unsafe IntPtr GetHeapPointer(object @object) { - var indirect = Unsafe.AsPointer(ref @object); - return **(IntPtr**)(&indirect); - } + private IReadOnlyList GetNestedLabels(ClrType type, ulong valueAddress, ulong offsetBase) { + if (type.IsPrimitive || !type.IsValueType) + return Array.Empty(); + + return CreateLabelsFromType(type, valueAddress, offsetBase + (uint)IntPtr.Size); + } + + private static unsafe IntPtr GetHeapPointer(object @object) { + var indirect = Unsafe.AsPointer(ref @object); + return **(IntPtr**)(&indirect); } } diff --git a/source/Container/Runtime/Utf8ValuePresenter.cs b/source/Container/Runtime/Utf8ValuePresenter.cs index 381d5a6c3..8183f0602 100644 --- a/source/Container/Runtime/Utf8ValuePresenter.cs +++ b/source/Container/Runtime/Utf8ValuePresenter.cs @@ -64,7 +64,10 @@ private void AppendValue(Span output, T value, int depth, ValuePresente case int i: AppendNumber(output, i, out byteCount); break; - case ICollection c: + case IReadOnlyCollection c: + AppendEnumerable(output, c, depth, limits, out byteCount); + break; + case IReadOnlyCollection c: AppendEnumerable(output, c, depth, limits, out byteCount); break; case ICollection c: diff --git a/source/Container/Runtime/VariantValue.cs b/source/Container/Runtime/VariantValue.cs index f50dbd5c3..e9ac88841 100644 --- a/source/Container/Runtime/VariantValue.cs +++ b/source/Container/Runtime/VariantValue.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; namespace SharpLab.Container.Runtime { - internal readonly partial struct VariantValue { + internal readonly struct VariantValue { private readonly VariantKind _kind; private readonly object? _objectValue; private readonly Union _unionValue; diff --git a/source/Directory.Build.props b/source/Directory.Build.props index 492312abd..5e23c604b 100644 --- a/source/Directory.Build.props +++ b/source/Directory.Build.props @@ -1,6 +1,6 @@ - 9.0 + 12.0 enable true RS1022; CS1030 diff --git a/source/Native.Profiler/Native.Profiler.vcxproj b/source/Native.Profiler/Native.Profiler.vcxproj index 2823b7395..37eb4d026 100644 --- a/source/Native.Profiler/Native.Profiler.vcxproj +++ b/source/Native.Profiler/Native.Profiler.vcxproj @@ -33,26 +33,26 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode diff --git a/source/NetFramework/Runtime/Inspect.cs b/source/NetFramework/Runtime/Inspect.cs index 0011d5520..5dc8b8c08 100644 --- a/source/NetFramework/Runtime/Inspect.cs +++ b/source/NetFramework/Runtime/Inspect.cs @@ -18,7 +18,7 @@ public static void Heap(object @object) { if (objectType == null) throw new Exception($"Failed to find object type for address 0x{address:X}."); - var objectSize = runtime.Heap.GetObjectSize(address, objectType); + var objectSize = runtime.Heap.GetObject(address, objectType).Size; // Move by one pointer size back -- Object Header, // see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/ diff --git a/source/NetFramework/Runtime/Runtime.csproj b/source/NetFramework/Runtime/Runtime.csproj index a2c9cf046..bb610009e 100644 --- a/source/NetFramework/Runtime/Runtime.csproj +++ b/source/NetFramework/Runtime/Runtime.csproj @@ -10,8 +10,8 @@ - + - + \ No newline at end of file diff --git a/source/NetFramework/Server/App_Start/Startup.cs b/source/NetFramework/Server/App_Start/Startup.cs index 511891951..e2788d1df 100644 --- a/source/NetFramework/Server/App_Start/Startup.cs +++ b/source/NetFramework/Server/App_Start/Startup.cs @@ -14,67 +14,67 @@ [assembly: OwinStartup(typeof(Startup), nameof(Startup.Configuration))] -namespace SharpLab.Server.Owin { - public class Startup { - public virtual void Configuration(IAppBuilder app) { - DotEnv.Load(); +namespace SharpLab.Server.Owin; - var corsPolicyTask = Task.FromResult(new CorsPolicy { - AllowAnyHeader = true, - AllowAnyMethod = true, - AllowAnyOrigin = true, - PreflightMaxAge = (long)StartupHelper.CorsPreflightMaxAge.TotalMilliseconds - }); - var corsOptions = new CorsOptions { - PolicyProvider = new CorsPolicyProvider { - PolicyResolver = r => corsPolicyTask - } - }; - app.UseCors(corsOptions); +public class Startup { + public virtual void Configuration(IAppBuilder app) { + DotEnv.Load(); - var container = CreateContainer(); - app.MapMirrorSharp( - "/mirrorsharp", - StartupHelper.CreateMirrorSharpOptions(container), - StartupHelper.CreateMirrorSharpServices(container) - ); + var corsPolicyTask = Task.FromResult(new CorsPolicy { + AllowAnyHeader = true, + AllowAnyMethod = true, + AllowAnyOrigin = true, + PreflightMaxAge = (long)StartupHelper.CorsPreflightMaxAge.TotalMilliseconds + }); + var corsOptions = new CorsOptions { + PolicyProvider = new CorsPolicyProvider { + PolicyResolver = r => corsPolicyTask + } + }; + app.UseCors(corsOptions); - app.Map("/status", a => a.Use((c, next) => { - c.Response.ContentType = "text/plain"; - return c.Response.WriteAsync("OK"); - })); + var container = CreateContainer(); + app.MapMirrorSharp( + "/mirrorsharp", + StartupHelper.CreateMirrorSharpOptions(container), + StartupHelper.CreateMirrorSharpServices(container) + ); - var monitor = container.Resolve(); - monitor.Event("Application Startup", null); - HostingEnvironment.RegisterObject(new ShutdownMonitor(monitor)); + app.Map("/status", a => a.Use((c, next) => { + c.Response.ContentType = "text/plain"; + return c.Response.WriteAsync("OK"); + })); - app.UseAutofacLifetimeScopeInjector(container); - } + var monitor = container.Resolve(); + monitor.Event("Application Startup", null); + HostingEnvironment.RegisterObject(new ShutdownMonitor(monitor)); - private IContainer CreateContainer() { - var builder = new ContainerBuilder(); - StartupHelper.ConfigureContainer(builder); - return builder.Build(); - } + app.UseAutofacLifetimeScopeInjector(container); + } - private class ShutdownMonitor : IRegisteredObject { - private readonly IMonitor _monitor; + private IContainer CreateContainer() { + var builder = new ContainerBuilder(); + StartupHelper.ConfigureContainer(builder); + return builder.Build(); + } - public ShutdownMonitor(IMonitor monitor) { - _monitor = monitor; - } + private class ShutdownMonitor : IRegisteredObject { + private readonly IMonitor _monitor; + + public ShutdownMonitor(IMonitor monitor) { + _monitor = monitor; + } - public void Stop(bool immediate) { - if (immediate) - return; - try { - _monitor.Event("Application Shutdown", null, new Dictionary { - { "Reason", HostingEnvironment.ShutdownReason.ToString() } - }); - } - catch (Exception ex) { - _monitor.Exception(ex, null); - } + public void Stop(bool immediate) { + if (immediate) + return; + try { + _monitor.Event("Application Shutdown", null, new Dictionary { + { "Reason", HostingEnvironment.ShutdownReason.ToString() } + }); + } + catch (Exception ex) { + _monitor.Exception(ex, null); } } } diff --git a/source/NetFramework/Server/Common/CommonModule.cs b/source/NetFramework/Server/Common/CommonModule.cs index 4144d27e5..22b22e166 100644 --- a/source/NetFramework/Server/Common/CommonModule.cs +++ b/source/NetFramework/Server/Common/CommonModule.cs @@ -7,50 +7,56 @@ using SharpLab.Server.Common.Internal; using SharpLab.Server.Common.Languages; -namespace SharpLab.Server.Common { - [UsedImplicitly] - public class CommonModule : Module { - protected override void Load(ContainerBuilder builder) { - RegisterExternals(builder); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - } - - private void RegisterExternals(ContainerBuilder builder) { - builder.RegisterInstance(new RecyclableMemoryStreamManager()) - .AsSelf(); - - builder.RegisterInstance>(() => new HttpClient()) - .As>() - .SingleInstance() - .PreserveExistingDefaults(); // allows tests and other overrides - - builder.RegisterType() - .As() - .SingleInstance(); - } +namespace SharpLab.Server.Common; + +[UsedImplicitly] +public class CommonModule : Module { + protected override void Load(ContainerBuilder builder) { + RegisterExternals(builder); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); + builder.RegisterType() + .As() + .SingleInstance() + .WithParameter("webAppName", webAppName); + } + + private void RegisterExternals(ContainerBuilder builder) { + builder.RegisterInstance(new RecyclableMemoryStreamManager()) + .AsSelf(); + + builder.RegisterInstance>(() => new HttpClient()) + .As>() + .SingleInstance() + .PreserveExistingDefaults(); // allows tests and other overrides + + builder.RegisterType() + .As() + .SingleInstance(); } } diff --git a/source/NetFramework/Server/Common/DotEnv.cs b/source/NetFramework/Server/Common/DotEnv.cs index e4cf492f3..249c15ab4 100644 --- a/source/NetFramework/Server/Common/DotEnv.cs +++ b/source/NetFramework/Server/Common/DotEnv.cs @@ -1,27 +1,27 @@ using System; using System.IO; -namespace SharpLab.Server.Common { - public static class DotEnv { - public static void Load() { - var rootPath = AppDomain.CurrentDomain.BaseDirectory; - if (rootPath == null) - return; +namespace SharpLab.Server.Common; - var envPath = Path.Combine(rootPath, ".env"); - if (!File.Exists(envPath)) - return; +public static class DotEnv { + public static void Load() { + var rootPath = AppDomain.CurrentDomain.BaseDirectory; + if (rootPath == null) + return; - foreach (var line in File.ReadLines(envPath)) { - var trimmed = line.Trim(); - if (trimmed == "" || trimmed.StartsWith("#")) - continue; - var parts = trimmed.Split(new[] { '=' }, 2); - var key = parts[0].TrimEnd(); - var value = parts[1].TrimStart(); + var envPath = Path.Combine(rootPath, ".env"); + if (!File.Exists(envPath)) + return; - Environment.SetEnvironmentVariable(key, value); - } + foreach (var line in File.ReadLines(envPath)) { + var trimmed = line.Trim(); + if (trimmed == "" || trimmed.StartsWith("#")) + continue; + var parts = trimmed.Split(['='], 2); + var key = parts[0].TrimEnd(); + var value = parts[1].TrimStart(); + + Environment.SetEnvironmentVariable(key, value); } } } diff --git a/source/NetFramework/Server/Common/EnvironmentHelper.cs b/source/NetFramework/Server/Common/EnvironmentHelper.cs new file mode 100644 index 000000000..60b045702 --- /dev/null +++ b/source/NetFramework/Server/Common/EnvironmentHelper.cs @@ -0,0 +1,10 @@ +using System; + +namespace SharpLab.Server.Common; + +public static class EnvironmentHelper { + public static string GetRequiredEnvironmentVariable(string name) { + return Environment.GetEnvironmentVariable(name) + ?? throw new Exception($"Environment variable {name} was not found"); + } +} diff --git a/source/NetFramework/Server/Common/FeatureTracker.cs b/source/NetFramework/Server/Common/FeatureTracker.cs new file mode 100644 index 000000000..f59ec2868 --- /dev/null +++ b/source/NetFramework/Server/Common/FeatureTracker.cs @@ -0,0 +1,35 @@ +using SharpLab.Server.Monitoring; + +namespace SharpLab.Server.Common; + +public class FeatureTracker : IFeatureTracker { + private readonly string _webAppName; + private readonly IOneDimensionMetricMonitor _branchMetricMonitor; + private readonly IOneDimensionMetricMonitor _languageMetricMonitor; + private readonly IOneDimensionMetricMonitor _targetMetricMonitor; + private readonly IOneDimensionMetricMonitor _optimizeMetricMonitor; + + public FeatureTracker(IMonitor monitor, string webAppName) { + _webAppName = webAppName; + _branchMetricMonitor = monitor.MetricSlow("feature", "Branch", "Branch"); + _languageMetricMonitor = monitor.MetricSlow("feature", "Language", "Language"); + _targetMetricMonitor = monitor.MetricSlow("feature", "Target", "Target"); + _optimizeMetricMonitor = monitor.MetricSlow("feature", "Optimize", "Optimize"); + } + + public void TrackBranch() { + _branchMetricMonitor.Track(_webAppName, 1); + } + + public void TrackLanguage(string languageName) { + _languageMetricMonitor.Track(languageName, 1); + } + + public void TrackTarget(string targetName) { + _targetMetricMonitor.Track(targetName, 1); + } + + public void TrackOptimize(string optimize) { + _optimizeMetricMonitor.Track(optimize, 1); + } +} diff --git a/source/NetFramework/Server/Common/IFeatureTracker.cs b/source/NetFramework/Server/Common/IFeatureTracker.cs new file mode 100644 index 000000000..373ce9b7c --- /dev/null +++ b/source/NetFramework/Server/Common/IFeatureTracker.cs @@ -0,0 +1,8 @@ +namespace SharpLab.Server.Common; + +public interface IFeatureTracker { + void TrackBranch(); + void TrackLanguage(string languageName); + void TrackTarget(string targetName); + void TrackOptimize(string optimize); +} \ No newline at end of file diff --git a/source/NetFramework/Server/Common/ILanguageAdapter.cs b/source/NetFramework/Server/Common/ILanguageAdapter.cs index 8fe919dfe..6ad14bf2a 100644 --- a/source/NetFramework/Server/Common/ILanguageAdapter.cs +++ b/source/NetFramework/Server/Common/ILanguageAdapter.cs @@ -3,18 +3,18 @@ using MirrorSharp.Advanced; using SharpLab.Server.Common.Internal; -namespace SharpLab.Server.Common { - public interface ILanguageAdapter { - string LanguageName { get; } +namespace SharpLab.Server.Common; - void SlowSetup(MirrorSharpOptions options); - void SetOptimize(IWorkSession session, string optimize); - void SetOptionsForTarget(IWorkSession session, string target); +public interface ILanguageAdapter { + string LanguageName { get; } - ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod); - ImmutableArray GetCallArgumentIdentifiers(IWorkSession session, int callStartLine, int callStartColumn); + void SlowSetup(MirrorSharpOptions options); + void SetOptimize(IWorkSession session, string optimize); + void SetOptionsForTarget(IWorkSession session, string target); - // Note: in some cases this Task is never resolved (e.g. if VB is never used) - AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } - } + ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod); + ImmutableArray GetCallArgumentIdentifiers(IWorkSession session, int callStartLine, int callStartColumn); + + // Note: in some cases this Task is never resolved (e.g. if VB is never used) + AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } } \ No newline at end of file diff --git a/source/NetFramework/Server/Common/ISecretsClient.cs b/source/NetFramework/Server/Common/ISecretsClient.cs new file mode 100644 index 000000000..1d5f5c85a --- /dev/null +++ b/source/NetFramework/Server/Common/ISecretsClient.cs @@ -0,0 +1,5 @@ +namespace SharpLab.Server.Common; + +public interface ISecretsClient { + string GetSecret(string key); +} \ No newline at end of file diff --git a/source/NetFramework/Server/Common/LanguageNames.cs b/source/NetFramework/Server/Common/LanguageNames.cs index c2ec52785..54ed93db4 100644 --- a/source/NetFramework/Server/Common/LanguageNames.cs +++ b/source/NetFramework/Server/Common/LanguageNames.cs @@ -1,10 +1,10 @@ using CodeAnalysis = Microsoft.CodeAnalysis; -namespace SharpLab.Server.Common { - public class LanguageNames { - public const string CSharp = CodeAnalysis.LanguageNames.CSharp; - public const string VisualBasic = CodeAnalysis.LanguageNames.VisualBasic; - public const string FSharp = CodeAnalysis.LanguageNames.FSharp; - public const string IL = "IL"; - } +namespace SharpLab.Server.Common; + +public class LanguageNames { + public const string CSharp = CodeAnalysis.LanguageNames.CSharp; + public const string VisualBasic = CodeAnalysis.LanguageNames.VisualBasic; + public const string FSharp = CodeAnalysis.LanguageNames.FSharp; + public const string IL = "IL"; } diff --git a/source/NetFramework/Server/Common/Languages/CSharpAdapter.cs b/source/NetFramework/Server/Common/Languages/CSharpAdapter.cs index 6e3b7204d..af6f4d70c 100644 --- a/source/NetFramework/Server/Common/Languages/CSharpAdapter.cs +++ b/source/NetFramework/Server/Common/Languages/CSharpAdapter.cs @@ -16,130 +16,130 @@ using SharpLab.Server.Compilation.Internal; using Binder = Microsoft.CSharp.RuntimeBinder.Binder; -namespace SharpLab.Server.Common.Languages { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class CSharpAdapter : ILanguageAdapter { - private static readonly LanguageVersion MaxLanguageVersion = Enum - .GetValues(typeof (LanguageVersion)) - .Cast() - .Where(v => v != LanguageVersion.Latest) // seems like latest got fixed at some point - .Max(); - private static readonly ImmutableArray ReleasePreprocessorSymbols = ImmutableArray.Create("__DEMO_EXPERIMENTAL__", "NETFRAMEWORK"); - private static readonly ImmutableArray DebugPreprocessorSymbols = ReleasePreprocessorSymbols.Add("DEBUG"); - - private readonly ImmutableList _references; - - public CSharpAdapter(IAssemblyReferenceCollector referenceCollector, IAssemblyDocumentationResolver documentationResolver) { - var referencedAssemblies = referenceCollector.SlowGetAllReferencedAssembliesRecursive( - // Essential - NetFrameworkRuntime.AssemblyOfValueTask, - NetFrameworkRuntime.AssemblyOfValueTuple, - NetFrameworkRuntime.AssemblyOfSpan, - typeof(Binder).Assembly, - - // Runtime - typeof(JitGenericAttribute).Assembly, - - // Requested - typeof(XDocument).Assembly, // System.Xml.Linq - typeof(IDataReader).Assembly, // System.Data - typeof(HttpUtility).Assembly // System.Web - ).ToImmutableList(); - - var assemblyReferenceTaskSource = new AssemblyReferenceDiscoveryTaskSource(); - assemblyReferenceTaskSource.Complete(referencedAssemblies.Select(a => a.Location).ToImmutableList()); - AssemblyReferenceDiscoveryTask = assemblyReferenceTaskSource.Task; - - _references = referencedAssemblies - .Select(a => (MetadataReference)MetadataReference.CreateFromFile(a.Location, documentation: documentationResolver.GetDocumentation(a))) - .ToImmutableList(); - } +namespace SharpLab.Server.Common.Languages; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class CSharpAdapter : ILanguageAdapter { + private static readonly LanguageVersion MaxLanguageVersion = Enum + .GetValues(typeof (LanguageVersion)) + .Cast() + .Where(v => v != LanguageVersion.Latest) // seems like latest got fixed at some point + .Max(); + private static readonly ImmutableArray ReleasePreprocessorSymbols = ImmutableArray.Create("__DEMO_EXPERIMENTAL__", "NETFRAMEWORK"); + private static readonly ImmutableArray DebugPreprocessorSymbols = ReleasePreprocessorSymbols.Add("DEBUG"); + + private readonly ImmutableList _references; + + public CSharpAdapter(IAssemblyReferenceCollector referenceCollector, IAssemblyDocumentationResolver documentationResolver) { + var referencedAssemblies = referenceCollector.SlowGetAllReferencedAssembliesRecursive( + // Essential + NetFrameworkRuntime.AssemblyOfValueTask, + NetFrameworkRuntime.AssemblyOfValueTuple, + NetFrameworkRuntime.AssemblyOfSpan, + typeof(Binder).Assembly, + + // Runtime + typeof(JitGenericAttribute).Assembly, + + // Requested + typeof(XDocument).Assembly, // System.Xml.Linq + typeof(IDataReader).Assembly, // System.Data + typeof(HttpUtility).Assembly // System.Web + ).ToImmutableList(); + + var assemblyReferenceTaskSource = new AssemblyReferenceDiscoveryTaskSource(); + assemblyReferenceTaskSource.Complete(referencedAssemblies.Select(a => a.Location).ToImmutableList()); + AssemblyReferenceDiscoveryTask = assemblyReferenceTaskSource.Task; + + _references = referencedAssemblies + .Select(a => (MetadataReference)MetadataReference.CreateFromFile(a.Location, documentation: documentationResolver.GetDocumentation(a))) + .ToImmutableList(); + } - public string LanguageName => LanguageNames.CSharp; - public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } - - public void SlowSetup(MirrorSharpOptions options) { - // ReSharper disable HeapView.ObjectAllocation.Evident - - options.CSharp.ParseOptions = new CSharpParseOptions( - MaxLanguageVersion, - preprocessorSymbols: DebugPreprocessorSymbols, - documentationMode: DocumentationMode.Diagnose - ); - options.CSharp.CompilationOptions = new CSharpCompilationOptions( - OutputKind.DynamicallyLinkedLibrary, - specificDiagnosticOptions: new Dictionary { - // CS1591: Missing XML comment for publicly visible type or member - { "CS1591", ReportDiagnostic.Suppress } - } - ); - options.CSharp.MetadataReferences = _references; - - // ReSharper restore HeapView.ObjectAllocation.Evident - } + public string LanguageName => LanguageNames.CSharp; + public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } + + public void SlowSetup(MirrorSharpOptions options) { + // ReSharper disable HeapView.ObjectAllocation.Evident + + options.CSharp.ParseOptions = new CSharpParseOptions( + MaxLanguageVersion, + preprocessorSymbols: DebugPreprocessorSymbols, + documentationMode: DocumentationMode.Diagnose + ); + options.CSharp.CompilationOptions = new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + specificDiagnosticOptions: new Dictionary { + // CS1591: Missing XML comment for publicly visible type or member + { "CS1591", ReportDiagnostic.Suppress } + } + ); + options.CSharp.MetadataReferences = _references; - public void SetOptimize(IWorkSession session, string optimize) { - var project = session.Roslyn.Project; - var parseOptions = ((CSharpParseOptions)project.ParseOptions!); - var compilationOptions = ((CSharpCompilationOptions)project.CompilationOptions!); - session.Roslyn.Project = project - .WithParseOptions(parseOptions.WithPreprocessorSymbols(optimize == Optimize.Debug ? DebugPreprocessorSymbols : ReleasePreprocessorSymbols)) - .WithCompilationOptions(compilationOptions.WithOptimizationLevel(optimize == Optimize.Debug ? OptimizationLevel.Debug : OptimizationLevel.Release)); - } + // ReSharper restore HeapView.ObjectAllocation.Evident + } - public void SetOptionsForTarget(IWorkSession session, string target) { - var outputKind = target != TargetNames.Run ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication; - var allowUnsafe = target != TargetNames.Run; + public void SetOptimize(IWorkSession session, string optimize) { + var project = session.Roslyn.Project; + var parseOptions = ((CSharpParseOptions)project.ParseOptions!); + var compilationOptions = ((CSharpCompilationOptions)project.CompilationOptions!); + session.Roslyn.Project = project + .WithParseOptions(parseOptions.WithPreprocessorSymbols(optimize == Optimize.Debug ? DebugPreprocessorSymbols : ReleasePreprocessorSymbols)) + .WithCompilationOptions(compilationOptions.WithOptimizationLevel(optimize == Optimize.Debug ? OptimizationLevel.Debug : OptimizationLevel.Release)); + } - var project = session.Roslyn.Project; - var options = ((CSharpCompilationOptions)project.CompilationOptions!); - session.Roslyn.Project = project.WithCompilationOptions( - options.WithOutputKind(outputKind).WithAllowUnsafe(allowUnsafe) - ); - } + public void SetOptionsForTarget(IWorkSession session, string target) { + var outputKind = target != TargetNames.Run ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication; + var allowUnsafe = target != TargetNames.Run; - public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { - var declaration = RoslynAdapterHelper.FindSyntaxNodeInSession(session, lineInMethod, columnInMethod) - ?.AncestorsAndSelf() - .FirstOrDefault(m => m is MemberDeclarationSyntax - || m is AnonymousFunctionExpressionSyntax - || m is LocalFunctionStatementSyntax); - - var parameters = declaration switch { - BaseMethodDeclarationSyntax m => m.ParameterList.Parameters, - ParenthesizedLambdaExpressionSyntax l => l.ParameterList.Parameters, - SimpleLambdaExpressionSyntax l => SyntaxFactory.SingletonSeparatedList(l.Parameter), - LocalFunctionStatementSyntax f => f.ParameterList.Parameters, - _ => SyntaxFactory.SeparatedList() - }; - - if (parameters.Count == 0) - return ImmutableArray.Empty; - - var results = new int[parameters.Count]; - for (var i = 0; i < parameters.Count; i++) { - results[i] = parameters[i].GetLocation().GetLineSpan().StartLinePosition.Line + 1; - } - return ImmutableArray.Create(results); + var project = session.Roslyn.Project; + var options = ((CSharpCompilationOptions)project.CompilationOptions!); + session.Roslyn.Project = project.WithCompilationOptions( + options.WithOutputKind(outputKind).WithAllowUnsafe(allowUnsafe) + ); + } + + public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { + var declaration = RoslynAdapterHelper.FindSyntaxNodeInSession(session, lineInMethod, columnInMethod) + ?.AncestorsAndSelf() + .FirstOrDefault(m => m is MemberDeclarationSyntax + || m is AnonymousFunctionExpressionSyntax + || m is LocalFunctionStatementSyntax); + + var parameters = declaration switch { + BaseMethodDeclarationSyntax m => m.ParameterList.Parameters, + ParenthesizedLambdaExpressionSyntax l => l.ParameterList.Parameters, + SimpleLambdaExpressionSyntax l => SyntaxFactory.SingletonSeparatedList(l.Parameter), + LocalFunctionStatementSyntax f => f.ParameterList.Parameters, + _ => SyntaxFactory.SeparatedList() + }; + + if (parameters.Count == 0) + return ImmutableArray.Empty; + + var results = new int[parameters.Count]; + for (var i = 0; i < parameters.Count; i++) { + results[i] = parameters[i].GetLocation().GetLineSpan().StartLinePosition.Line + 1; } + return ImmutableArray.Create(results); + } - public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { - var call = RoslynAdapterHelper.FindSyntaxNodeInSession(session, callStartLine, callStartColumn) - ?.AncestorsAndSelf() - .OfType() - .FirstOrDefault(); - if (call == null) - return ImmutableArray.Empty; - - var arguments = call.ArgumentList.Arguments; - if (arguments.Count == 0) - return ImmutableArray.Empty; - - var results = new string?[arguments.Count]; - for (var i = 0; i < arguments.Count; i++) { - results[i] = (arguments[i].Expression is IdentifierNameSyntax n) ? n.Identifier.ValueText : null; - } - return ImmutableArray.Create(results); + public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { + var call = RoslynAdapterHelper.FindSyntaxNodeInSession(session, callStartLine, callStartColumn) + ?.AncestorsAndSelf() + .OfType() + .FirstOrDefault(); + if (call == null) + return ImmutableArray.Empty; + + var arguments = call.ArgumentList.Arguments; + if (arguments.Count == 0) + return ImmutableArray.Empty; + + var results = new string?[arguments.Count]; + for (var i = 0; i < arguments.Count; i++) { + results[i] = (arguments[i].Expression is IdentifierNameSyntax n) ? n.Identifier.ValueText : null; } + return ImmutableArray.Create(results); } } diff --git a/source/NetFramework/Server/Common/Languages/FSharpAdapter.cs b/source/NetFramework/Server/Common/Languages/FSharpAdapter.cs index ff8cf131b..c4efb4867 100644 --- a/source/NetFramework/Server/Common/Languages/FSharpAdapter.cs +++ b/source/NetFramework/Server/Common/Languages/FSharpAdapter.cs @@ -15,67 +15,66 @@ using SharpLab.Server.Common.Internal; using SharpLab.Server.Compilation.Internal; -namespace SharpLab.Server.Common.Languages { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class FSharpAdapter : ILanguageAdapter { - private readonly AssemblyReferenceDiscoveryTaskSource _referencedAssembliesTaskSource = new AssemblyReferenceDiscoveryTaskSource(); - private readonly IAssemblyReferenceCollector _referenceCollector; +namespace SharpLab.Server.Common.Languages; - public string LanguageName => LanguageNames.FSharp; - public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask => _referencedAssembliesTaskSource.Task; +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class FSharpAdapter : ILanguageAdapter { + private readonly AssemblyReferenceDiscoveryTaskSource _referencedAssembliesTaskSource = new(); + private readonly IAssemblyReferenceCollector _referenceCollector; - public FSharpAdapter(IAssemblyReferenceCollector referenceCollector) { - _referenceCollector = referenceCollector; - } + public string LanguageName => LanguageNames.FSharp; + public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask => _referencedAssembliesTaskSource.Task; - public void SlowSetup(MirrorSharpOptions options) { - options.EnableFSharp(o => { - var assemblyOfObject = typeof(object).Assembly; - var referencedAssemblies = _referenceCollector.SlowGetAllReferencedAssembliesRecursive( - // Essential - assemblyOfObject, - NetFrameworkRuntime.AssemblyOfValueTask, - typeof(TaskExtensions).Assembly, - typeof(FSharpOption<>).Assembly, + public FSharpAdapter(IAssemblyReferenceCollector referenceCollector) { + _referenceCollector = referenceCollector; + } + + public void SlowSetup(MirrorSharpOptions options) { + options.EnableFSharp(o => { + var assemblyOfObject = typeof(object).Assembly; + var referencedAssemblies = _referenceCollector.SlowGetAllReferencedAssembliesRecursive( + // Essential + assemblyOfObject, + NetFrameworkRuntime.AssemblyOfValueTask, + typeof(TaskExtensions).Assembly, + typeof(FSharpOption<>).Assembly, - // Runtime - typeof(JitGenericAttribute).Assembly, + // Runtime + typeof(JitGenericAttribute).Assembly, - // Requested - typeof(XDocument).Assembly, // System.Xml.Linq - typeof(IDataReader).Assembly, // System.Data - typeof(HttpUtility).Assembly // System.Web - ); + // Requested + typeof(XDocument).Assembly, // System.Xml.Linq + typeof(IDataReader).Assembly, // System.Data + typeof(HttpUtility).Assembly // System.Web + ); - var referencedAssemblyPaths = referencedAssemblies.Select(a => a.Location).ToImmutableArray(); - if (assemblyOfObject.GetName().Name != "mscorlib") { - var mscorlibPath = Path.Combine(Path.GetDirectoryName(assemblyOfObject.Location)!, "mscorlib.dll"); - referencedAssemblyPaths = referencedAssemblyPaths.Add(mscorlibPath); - } - _referencedAssembliesTaskSource.Complete(referencedAssemblyPaths); - o.AssemblyReferencePaths = referencedAssemblyPaths; - }); - } + var referencedAssemblyPaths = referencedAssemblies.Select(a => a.Location).ToImmutableArray(); + if (assemblyOfObject.GetName().Name != "mscorlib") { + var mscorlibPath = Path.Combine(Path.GetDirectoryName(assemblyOfObject.Location)!, "mscorlib.dll"); + referencedAssemblyPaths = referencedAssemblyPaths.Add(mscorlibPath); + } + _referencedAssembliesTaskSource.Complete(referencedAssemblyPaths); + o.AssemblyReferencePaths = referencedAssemblyPaths; + }); + } - public void SetOptimize([NotNull] IWorkSession session, [NotNull] string optimize) { - var debug = optimize == Optimize.Debug; - var fsharp = session.FSharp(); - fsharp.ProjectOptions = fsharp.ProjectOptions - .WithOtherOptionDebug(debug) - .WithOtherOptionOptimize(!debug) - .WithOtherOptionDefine("DEBUG", debug); - } + public void SetOptimize([NotNull] IWorkSession session, [NotNull] string optimize) { + var debug = optimize == Optimize.Debug; + var fsharp = session.FSharp(); + fsharp.ProjectOptions = fsharp.ProjectOptions + .WithOtherOptionOptimize(!debug) + .WithOtherOptionDefine("DEBUG", debug); + } - public void SetOptionsForTarget([NotNull] IWorkSession session, [NotNull] string target) { - // I don't use `exe` for Run, see FSharpEntryPointRewriter - } + public void SetOptionsForTarget([NotNull] IWorkSession session, [NotNull] string target) { + // I don't use `exe` for Run, see FSharpEntryPointRewriter + } - public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { - return ImmutableArray.Empty; // not supported yet - } + public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { + return ImmutableArray.Empty; // not supported yet + } - public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { - return ImmutableArray.Empty; // not supported yet - } + public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { + return ImmutableArray.Empty; // not supported yet } } \ No newline at end of file diff --git a/source/NetFramework/Server/Common/TargetNames.cs b/source/NetFramework/Server/Common/TargetNames.cs index 37d0f5316..40dfd46c8 100644 --- a/source/NetFramework/Server/Common/TargetNames.cs +++ b/source/NetFramework/Server/Common/TargetNames.cs @@ -1,11 +1,11 @@ -namespace SharpLab.Server.Common { - public static class TargetNames { - public const string CSharp = LanguageNames.CSharp; - public const string IL = "IL"; - public const string Ast = "AST"; - public const string JitAsm = "JIT ASM"; - public const string Run = "Run"; - public const string Verify = "Verify"; - public const string Explain = "Explain"; - } +namespace SharpLab.Server.Common; + +public static class TargetNames { + public const string CSharp = LanguageNames.CSharp; + public const string IL = "IL"; + public const string Ast = "AST"; + public const string JitAsm = "JIT ASM"; + public const string Run = "Run"; + public const string Verify = "Verify"; + public const string Explain = "Explain"; } \ No newline at end of file diff --git a/source/NetFramework/Server/Compilation/Compiler.cs b/source/NetFramework/Server/Compilation/Compiler.cs index abe606620..ddfc07596 100644 --- a/source/NetFramework/Server/Compilation/Compiler.cs +++ b/source/NetFramework/Server/Compilation/Compiler.cs @@ -6,11 +6,8 @@ using System.Threading; using System.Threading.Tasks; using FSharp.Compiler.Diagnostics; -using FSharp.Compiler.Syntax; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; -using Microsoft.FSharp.Collections; -using Microsoft.FSharp.Control; using Microsoft.IO; using MirrorSharp.Advanced; using MirrorSharp.FSharp.Advanced; @@ -19,108 +16,97 @@ using Mobius.ILasm.Core; using SharpLab.Server.Compilation.Internal; -namespace SharpLab.Server.Compilation { - public class Compiler : ICompiler { - private static readonly EmitOptions RoslynEmitOptions = new( - // TODO: try out embedded - debugInformationFormat: DebugInformationFormat.PortablePdb - ); - private readonly RecyclableMemoryStreamManager _memoryStreamManager; +namespace SharpLab.Server.Compilation; - public Compiler(RecyclableMemoryStreamManager memoryStreamManager) { - _memoryStreamManager = memoryStreamManager; - } +public class Compiler : ICompiler { + private static readonly EmitOptions RoslynEmitOptions = new( + // TODO: try out embedded + debugInformationFormat: DebugInformationFormat.PortablePdb + ); + private readonly RecyclableMemoryStreamManager _memoryStreamManager; - public async Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( - MemoryStream assemblyStream, - MemoryStream? symbolStream, - IWorkSession session, - IList diagnostics, - CancellationToken cancellationToken - ) { - if (session.IsFSharp()) { - var compiled = await TryCompileFSharpToStreamAsync(assemblyStream, session, diagnostics, cancellationToken).ConfigureAwait(false); - return (compiled, false); - } + public Compiler(RecyclableMemoryStreamManager memoryStreamManager) { + _memoryStreamManager = memoryStreamManager; + } - if (session.IsIL()) { - var compiled = TryCompileILToStream(assemblyStream, session, diagnostics); - return (compiled, false); - } + public async Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( + MemoryStream assemblyStream, + MemoryStream? symbolStream, + IWorkSession session, + IList diagnostics, + CancellationToken cancellationToken + ) { + if (session.IsFSharp()) { + var compiled = await TryCompileFSharpToStreamAsync(assemblyStream, session, diagnostics, cancellationToken).ConfigureAwait(false); + return (compiled, false); + } - #warning TODO: Revisit after https: //github.com/dotnet/docs/issues/14784 - var compilation = (await session.Roslyn.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; - var emitResult = compilation.Emit(assemblyStream, pdbStream: symbolStream, options: RoslynEmitOptions); - if (!emitResult.Success) { - foreach (var diagnostic in emitResult.Diagnostics) { - diagnostics.Add(diagnostic); - } + if (session.IsIL()) { + var compiled = TryCompileILToStream(assemblyStream, session, diagnostics); + return (compiled, false); + } - return (false, false); + #warning TODO: Revisit after https: //github.com/dotnet/docs/issues/14784 + var compilation = (await session.Roslyn.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; + var emitResult = compilation.Emit(assemblyStream, pdbStream: symbolStream, options: RoslynEmitOptions); + if (!emitResult.Success) { + foreach (var diagnostic in emitResult.Diagnostics) { + diagnostics.Add(diagnostic); } - return (true, true); + return (false, false); } - private async Task TryCompileFSharpToStreamAsync( - MemoryStream assemblyStream, - IWorkSession session, - IList diagnostics, - CancellationToken cancellationToken - ) { - var fsharp = session.FSharp(); + return (true, true); + } - // GetLastParseResults are guaranteed to be available here as MirrorSharp's SlowUpdate does the parse - var parsed = fsharp.GetLastParseResults()!; - using (var virtualAssemblyFile = FSharpFileSystem.RegisterVirtualFile(assemblyStream)) { - var compiled = await FSharpAsync.StartAsTask(fsharp.Checker.Compile( - FSharpList.Cons(parsed.ParseTree, FSharpList.Empty), - "_", virtualAssemblyFile.Path, - fsharp.AssemblyReferencePathsAsFSharpList, - pdbFile: null, - executable: false, //fsharp.ProjectOptions.OtherOptions.Contains("--target:exe"), - noframework: true, - userOpName: null - ), null, cancellationToken).ConfigureAwait(false); - foreach (var diagnostic in compiled.Item1) { - // no reason to add warnings as check would have added them anyways - if (diagnostic.Severity.Tag == FSharpDiagnosticSeverity.Tags.Error) - diagnostics.Add(fsharp.ConvertToDiagnostic(diagnostic)); - } + private async Task TryCompileFSharpToStreamAsync( + MemoryStream assemblyStream, + IWorkSession session, + IList diagnostics, + CancellationToken cancellationToken + ) { + var fsharp = session.FSharp(); + var compiled = await fsharp.CompileAsync(assemblyStream, cancellationToken) + .ConfigureAwait(false); - return assemblyStream.Length > 0; - } + foreach (var diagnostic in compiled.Item1) { + // no reason to add warnings as check would have added them anyways + if (diagnostic.Severity.Tag == FSharpDiagnosticSeverity.Tags.Error) + diagnostics.Add(fsharp.ConvertToDiagnostic(diagnostic)); } - private static readonly DriverSettings ILDriverSettings = new() { - ResourceResolver = ILNullResourceResolver.Default - }; - private bool TryCompileILToStream(MemoryStream assemblyStream, IWorkSession session, IList diagnostics) { - var il = (IILSessionInternal)session.IL(); - var ilText = il.GetText(); + return assemblyStream.Length > 0; + } - // TODO: See if we can get offset from the library instead - var lineColumnMap = ILLineColumnMap.BuildFor(ilText); - var logger = new ILCompilationLogger(diagnostics, lineColumnMap); - var driver = new Driver(logger, il.Target, ILDriverSettings); + private static readonly DriverSettings ILDriverSettings = new() { + ResourceResolver = ILNullResourceResolver.Default + }; + private bool TryCompileILToStream(MemoryStream assemblyStream, IWorkSession session, IList diagnostics) { + var il = (IILSessionInternal)session.IL(); + var ilText = il.GetText(); - var sourceBytesLength = Encoding.UTF8.GetByteCount(ilText); - var sourceBytes = ArrayPool.Shared.Rent(sourceBytesLength); - try { - Encoding.UTF8.GetBytes(ilText, 0, ilText.Length, sourceBytes, 0); - using var sourceStream = (RecyclableMemoryStream)_memoryStreamManager.GetStream("Compiler-IL", sourceBytes, 0, sourceBytesLength); + // TODO: See if we can get offset from the library instead + var lineColumnMap = ILLineColumnMap.BuildFor(ilText); + var logger = new ILCompilationLogger(diagnostics, lineColumnMap); + var driver = new Driver(logger, il.Target, ILDriverSettings); - try { - return driver.Assemble(new[] { sourceStream }, assemblyStream); - } - catch (Exception ex) when (ex.GetType().Name.StartsWith("yy")) { - // These are also reported through the logger, so will be reported as diagnostics - return false; - } + var sourceBytesLength = Encoding.UTF8.GetByteCount(ilText); + var sourceBytes = ArrayPool.Shared.Rent(sourceBytesLength); + try { + Encoding.UTF8.GetBytes(ilText, 0, ilText.Length, sourceBytes, 0); + using var sourceStream = (RecyclableMemoryStream)_memoryStreamManager.GetStream("Compiler-IL", sourceBytes, 0, sourceBytesLength); + + try { + return driver.Assemble(new[] { sourceStream }, assemblyStream); } - finally { - ArrayPool.Shared.Return(sourceBytes); + catch (Exception ex) when (ex.GetType().Name.StartsWith("yy")) { + // These are also reported through the logger, so will be reported as diagnostics + return false; } } + finally { + ArrayPool.Shared.Return(sourceBytes); + } } } \ No newline at end of file diff --git a/source/NetFramework/Server/Decompilation/AstOnly/FSharpAstTarget.cs b/source/NetFramework/Server/Decompilation/AstOnly/FSharpAstTarget.cs index 30c7db597..e93ef3a44 100644 --- a/source/NetFramework/Server/Decompilation/AstOnly/FSharpAstTarget.cs +++ b/source/NetFramework/Server/Decompilation/AstOnly/FSharpAstTarget.cs @@ -14,335 +14,336 @@ using FSharp.Compiler.Syntax; using Range = FSharp.Compiler.Text.Range; -namespace SharpLab.Server.Decompilation.AstOnly { - public class FSharpAstTarget : IAstTarget { - private delegate void SerializeChildAction(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted, IFSharpSession session); - private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted, IFSharpSession session); - private delegate Range GetRangeFunc(object target); - - private static readonly string SyntaxNamespace = typeof(Ident).Namespace!; - private static readonly Lazy> TopLevelAstTypes = new( - () => typeof(Ident).Assembly.GetTypes().Where(t => t.Namespace == SyntaxNamespace && !t.IsNested).ToList(), - LazyThreadSafetyMode.ExecutionAndPublication - ); - - private static readonly ConcurrentDictionary> ChildrenSerializers = new(); - private static readonly ConcurrentDictionary> RangeGetters = new(); - private static readonly Lazy>> TagNameGetters = - new(SlowCompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication); - private static readonly Lazy>> ConstValueGetters = - new(SlowCompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication); - private static readonly Lazy> AstTypeNames = - new(SlowCollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication); - - private static class Methods { - // ReSharper disable MemberHidesStaticFromOuterClass - // ReSharper disable HeapView.DelegateAllocation - public static readonly MethodInfo SerializeNode = - ((SerializeChildAction)FSharpAstTarget.SerializeNode).Method.GetGenericMethodDefinition(); - public static readonly MethodInfo SerializeList = - ((SerializeChildAction>)FSharpAstTarget.SerializeList).Method.GetGenericMethodDefinition(); - public static readonly MethodInfo SerializeIdent = - ((SerializeChildAction)FSharpAstTarget.SerializeIdent).Method; - public static readonly MethodInfo SerializeIdentList = - ((SerializeChildAction>)FSharpAstTarget.SerializeIdentList).Method; - public static readonly MethodInfo SerializeEnum = - ((SerializeChildAction)FSharpAstTarget.SerializeEnum).Method.GetGenericMethodDefinition(); - // ReSharper restore HeapView.DelegateAllocation - // ReSharper restore MemberHidesStaticFromOuterClass - } +namespace SharpLab.Server.Decompilation.AstOnly; + +public class FSharpAstTarget : IAstTarget { + private delegate void SerializeChildAction(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted, IFSharpSession session); + private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted, IFSharpSession session); + private delegate Range GetRangeFunc(object target); + + private static readonly string SyntaxNamespace = typeof(Ident).Namespace!; + private static readonly Lazy> TopLevelAstTypes = new( + () => typeof(Ident).Assembly.GetTypes().Where(t => t.Namespace == SyntaxNamespace && !t.IsNested).ToList(), + LazyThreadSafetyMode.ExecutionAndPublication + ); + + private static readonly ConcurrentDictionary> ChildrenSerializers = new(); + private static readonly ConcurrentDictionary> RangeGetters = new(); + private static readonly Lazy>> TagNameGetters = + new(SlowCompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication); + private static readonly Lazy>> ConstValueGetters = + new(SlowCompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication); + private static readonly Lazy> AstTypeNames = + new(SlowCollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication); + + private static class Methods { + // ReSharper disable MemberHidesStaticFromOuterClass + // ReSharper disable HeapView.DelegateAllocation + public static readonly MethodInfo SerializeNode = + ((SerializeChildAction)FSharpAstTarget.SerializeNode).Method.GetGenericMethodDefinition(); + public static readonly MethodInfo SerializeList = + ((SerializeChildAction>)FSharpAstTarget.SerializeList).Method.GetGenericMethodDefinition(); + public static readonly MethodInfo SerializeIdent = + ((SerializeChildAction)FSharpAstTarget.SerializeIdent).Method; + public static readonly MethodInfo SerializeIdentList = + ((SerializeChildAction>)FSharpAstTarget.SerializeIdentList).Method; + public static readonly MethodInfo SerializeEnum = + ((SerializeChildAction)FSharpAstTarget.SerializeEnum).Method.GetGenericMethodDefinition(); + // ReSharper restore HeapView.DelegateAllocation + // ReSharper restore MemberHidesStaticFromOuterClass + } - private static class EnumCache - where TEnum : struct, IFormattable { - public static readonly IReadOnlyDictionary Strings = Enum.GetValues(typeof(TEnum)).Cast().ToDictionary(e => e, e => e.ToString("G", null)); - } + private static class EnumCache + where TEnum : struct, IFormattable { + public static readonly IReadOnlyDictionary Strings = Enum.GetValues(typeof(TEnum)).Cast().ToDictionary(e => e, e => e.ToString("G", null)); + } - public Task GetAstAsync(IWorkSession session, CancellationToken cancellationToken) { - var parseResult = session.FSharp().GetLastParseResults(); - if (parseResult == null) - throw new InvalidOperationException("Current session does not include F# parse results yet."); - return Task.FromResult((object)parseResult.ParseTree); - } + public Task GetAstAsync(IWorkSession session, CancellationToken cancellationToken) { + var parseResult = session.FSharp().GetLastParseResults(); + if (parseResult == null) + throw new InvalidOperationException("Current session does not include F# parse results yet."); + return Task.FromResult((object)parseResult.ParseTree); + } - public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) { - var root = ((ParsedInput.ImplFile)ast).Item; - writer.WriteStartArray(); - var childrenStarted = true; - SerializeNode(root, writer, null, ref childrenStarted, session.FSharp()); - writer.WriteEndArray(); - } + public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) { + var root = ((ParsedInput.ImplFile)ast).Item; + writer.WriteStartArray(); + var childrenStarted = true; + SerializeNode(root, writer, null, ref childrenStarted, session.FSharp()); + writer.WriteEndArray(); + } - private static void SerializeNode(T node, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where T: notnull - { - EnsureChildrenStarted(ref parentChildrenStarted, writer); - writer.WriteStartObject(); - var nodeType = node.GetType(); - writer.WriteProperty("kind", AstTypeNames.Value[nodeType]); - if (parentPropertyName != null) - writer.WriteProperty("property", parentPropertyName); - - if (node is SynConst @const) { - writer.WriteProperty("type", "token"); - if (@const is SynConst.String @string) { - writer.WritePropertyName("value"); - writer.WriteValueFromParts("\"", @string.text, "\""); - } - else if (@const is SynConst.Char @char) { - writer.WritePropertyName("value"); - writer.WriteValueFromParts("'", @char.Item, "'"); - } - else { - if (ConstValueGetters.Value.TryGetValue(nodeType, out var getter)) { - writer.WritePropertyName("value"); - writer.WriteValue(getter(@const)); - } - } + private static void SerializeNode(T node, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where T: notnull + { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + writer.WriteStartObject(); + var nodeType = node.GetType(); + writer.WriteProperty("kind", AstTypeNames.Value[nodeType]); + if (parentPropertyName != null) + writer.WriteProperty("property", parentPropertyName); + + if (node is SynConst @const) { + writer.WriteProperty("type", "token"); + if (@const is SynConst.String @string) { + writer.WritePropertyName("value"); + writer.WriteValueFromParts("\"", @string.text, "\""); + } + else if (@const is SynConst.Char @char) { + writer.WritePropertyName("value"); + writer.WriteValueFromParts("'", @char.Item, "'"); } else { - writer.WriteProperty("type", nodeType.IsValueType ? "value" : "node"); - var tagName = GetTagName(node); - if (tagName != null) - writer.WriteProperty("value", tagName); + if (ConstValueGetters.Value.TryGetValue(nodeType, out var getter)) { + writer.WritePropertyName("value"); + writer.WriteValue(getter(@const)); + } } - var rangeGetter = GetRangeGetter(nodeType); - if (rangeGetter != null) - SerializeRangeProperty(rangeGetter(node), writer, session); + } + else { + writer.WriteProperty("type", nodeType.IsValueType ? "value" : "node"); + var tagName = GetTagName(node); + if (tagName != null) + writer.WriteProperty("value", tagName); + } + var rangeGetter = GetRangeGetter(nodeType); + if (rangeGetter != null) + SerializeRangeProperty(rangeGetter(node), writer, session); + + var childrenStarted = false; + GetChildrenSerializer(nodeType).Invoke(node, writer, ref childrenStarted, session); + EnsureChildrenEnded(childrenStarted, writer); + writer.WriteEndObject(); + } - var childrenStarted = false; - GetChildrenSerializer(nodeType).Invoke(node, writer, ref childrenStarted, session); - EnsureChildrenEnded(childrenStarted, writer); - writer.WriteEndObject(); + private static void SerializeList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where T: notnull + { + foreach (var item in list) { + SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted, session); } + } - private static void SerializeList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where T: notnull - { - foreach (var item in list) { - SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted, session); - } + private static void SerializeIdent(Ident ident, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + writer.WriteStartObject(); + writer.WriteProperty("type", "token"); + writer.WriteProperty("kind", "Ident"); + if (parentPropertyName != null) + writer.WriteProperty("property", parentPropertyName); + writer.WriteProperty("value", ident.idText); + SerializeRangeProperty(ident.idRange, writer, session); + writer.WriteEndObject(); + } + + private static void SerializeIdentList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { + foreach (var ident in list) { + SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted, session); } + } - private static void SerializeIdent(Ident ident, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { - EnsureChildrenStarted(ref parentChildrenStarted, writer); + private static void SerializeEnum(TEnum value, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where TEnum : struct, IFormattable { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + if (parentPropertyName != null) { writer.WriteStartObject(); - writer.WriteProperty("type", "token"); - writer.WriteProperty("kind", "Ident"); - if (parentPropertyName != null) - writer.WriteProperty("property", parentPropertyName); - writer.WriteProperty("value", ident.idText); - SerializeRangeProperty(ident.idRange, writer, session); + writer.WriteProperty("type", "value"); + writer.WriteProperty("property", parentPropertyName); + writer.WriteProperty("value", EnumCache.Strings[value]); writer.WriteEndObject(); } - - private static void SerializeIdentList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { - foreach (var ident in list) { - SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted, session); - } + else { + writer.WriteValue(EnumCache.Strings[value]); } + } - private static void SerializeEnum(TEnum value, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where TEnum : struct, IFormattable { - EnsureChildrenStarted(ref parentChildrenStarted, writer); - if (parentPropertyName != null) { - writer.WriteStartObject(); - writer.WriteProperty("type", "value"); - writer.WriteProperty("property", parentPropertyName); - writer.WriteProperty("value", EnumCache.Strings[value]); - writer.WriteEndObject(); - } - else { - writer.WriteValue(EnumCache.Strings[value]); - } - } + private static void SerializeRangeProperty(Range range, IFastJsonWriter writer, IFSharpSession session) { + writer.WritePropertyName("range"); + var startOffset = session.ConvertToOffset(range.StartLine, range.StartColumn); + var endOffset = session.ConvertToOffset(range.EndLine, range.EndColumn); + writer.WriteValueFromParts(startOffset, '-', endOffset); + } - private static void SerializeRangeProperty(Range range, IFastJsonWriter writer, IFSharpSession session) { - writer.WritePropertyName("range"); - var startOffset = session.ConvertToOffset(range.StartLine, range.StartColumn); - var endOffset = session.ConvertToOffset(range.EndLine, range.EndColumn); - writer.WriteValueFromParts(startOffset, '-', endOffset); - } + private static void EnsureChildrenStarted(ref bool childrenStarted, IFastJsonWriter writer) { + if (childrenStarted) + return; + writer.WritePropertyStartArray("children"); + childrenStarted = true; + } - private static void EnsureChildrenStarted(ref bool childrenStarted, IFastJsonWriter writer) { - if (childrenStarted) - return; - writer.WritePropertyStartArray("children"); - childrenStarted = true; - } + private static void EnsureChildrenEnded(bool childrenStarted, IFastJsonWriter writer) { + if (!childrenStarted) + return; + writer.WriteEndArray(); + } - private static void EnsureChildrenEnded(bool childrenStarted, IFastJsonWriter writer) { - if (!childrenStarted) - return; - writer.WriteEndArray(); + private static SerializeChildrenAction GetChildrenSerializer(Type type) { + if (!ChildrenSerializers.TryGetValue(type, out var lazySerialize)) { + lazySerialize = ChildrenSerializers.GetOrAdd( + type, + t => new(() => SlowCompileChildrenSerializer(t), LazyThreadSafetyMode.ExecutionAndPublication) + ); } - private static SerializeChildrenAction GetChildrenSerializer(Type type) { - if (!ChildrenSerializers.TryGetValue(type, out var lazySerialize)) { - lazySerialize = ChildrenSerializers.GetOrAdd( - type, - t => new(() => SlowCompileChildrenSerializer(t), LazyThreadSafetyMode.ExecutionAndPublication) - ); - } + return lazySerialize.Value; + } - return lazySerialize.Value; + private static SerializeChildrenAction SlowCompileChildrenSerializer(Type type) { + var nodeAsObject = Expression.Parameter(typeof(object)); + var writer = Expression.Parameter(typeof(IFastJsonWriter)); + var refChildrenStarted = Expression.Parameter(typeof(bool).MakeByRefType()); + var session = Expression.Parameter(typeof(IFSharpSession)); + + var node = Expression.Variable(type); + var body = new List { + Expression.Assign(node, Expression.Convert(nodeAsObject, type)) + }; + + foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { + if (ShouldSkipNodeProperty(type, property)) + continue; + var propertyType = property.PropertyType; + var method = SlowGetMethodToSerialize(propertyType); + if (method == null) + continue; + + var propertyName = property.Name; + if (Regex.IsMatch(propertyName, @"^Item\d*$")) + propertyName = null; + body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted, session)); } - private static SerializeChildrenAction SlowCompileChildrenSerializer(Type type) { - var nodeAsObject = Expression.Parameter(typeof(object)); - var writer = Expression.Parameter(typeof(IFastJsonWriter)); - var refChildrenStarted = Expression.Parameter(typeof(bool).MakeByRefType()); - var session = Expression.Parameter(typeof(IFSharpSession)); - - var node = Expression.Variable(type); - var body = new List { - Expression.Assign(node, Expression.Convert(nodeAsObject, type)) - }; + return Expression.Lambda( + Expression.Block(new[] { node }, body), + nodeAsObject, writer, refChildrenStarted, session + ).Compile(); + } - foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { - if (ShouldSkipNodeProperty(type, property)) - continue; - var propertyType = property.PropertyType; - var method = SlowGetMethodToSerialize(propertyType); - if (method == null) - continue; + private static MethodInfo? SlowGetMethodToSerialize(Type propertyType) { + if (propertyType == typeof(Ident)) + return Methods.SerializeIdent; - var propertyName = property.Name; - if (Regex.IsMatch(propertyName, @"^Item\d*$")) - propertyName = null; - body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted, session)); - } + if (propertyType == typeof(FSharpList)) + return Methods.SerializeIdentList; - return Expression.Lambda( - Expression.Block(new[] { node }, body), - nodeAsObject, writer, refChildrenStarted, session - ).Compile(); + if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(FSharpList<>)) { + var elementType = propertyType.GetGenericArguments()[0]; + if (!IsNodeType(elementType)) + return null; + return Methods.SerializeList.MakeGenericMethod(elementType); } - private static MethodInfo? SlowGetMethodToSerialize(Type propertyType) { - if (propertyType == typeof(Ident)) - return Methods.SerializeIdent; - - if (propertyType == typeof(FSharpList)) - return Methods.SerializeIdentList; - - if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(FSharpList<>)) { - var elementType = propertyType.GetGenericArguments()[0]; - if (!IsNodeType(elementType)) - return null; - return Methods.SerializeList.MakeGenericMethod(elementType); - } - - if (!IsNodeType(propertyType)) - return null; + if (!IsNodeType(propertyType)) + return null; - if (propertyType.IsEnum) - return Methods.SerializeEnum.MakeGenericMethod(propertyType); + if (propertyType.IsEnum) + return Methods.SerializeEnum.MakeGenericMethod(propertyType); - return Methods.SerializeNode.MakeGenericMethod(propertyType); - } + return Methods.SerializeNode.MakeGenericMethod(propertyType); + } - private static GetRangeFunc? GetRangeGetter(Type type) { - return RangeGetters.GetOrAdd( - type, - t => new Lazy(() => CompileRangeGetter(t), LazyThreadSafetyMode.ExecutionAndPublication) - ).Value; - } + private static GetRangeFunc? GetRangeGetter(Type type) { + return RangeGetters.GetOrAdd( + type, + t => new Lazy(() => CompileRangeGetter(t), LazyThreadSafetyMode.ExecutionAndPublication) + ).Value; + } - private static GetRangeFunc? CompileRangeGetter(Type type) { - var rangeProperty = type.GetProperty("Range"); - if (rangeProperty == null) - return null; + private static GetRangeFunc? CompileRangeGetter(Type type) { + var rangeProperty = type.GetProperty("Range"); + if (rangeProperty == null) + return null; - var nodeAsObject = Expression.Parameter(typeof(object)); - var body = Expression.Property(Expression.Convert(nodeAsObject, type), rangeProperty); + var nodeAsObject = Expression.Parameter(typeof(object)); + var body = Expression.Property(Expression.Convert(nodeAsObject, type), rangeProperty); - return Expression.Lambda(body, new[] { nodeAsObject }).Compile(); - } + return Expression.Lambda(body, new[] { nodeAsObject }).Compile(); + } - private static bool ShouldSkipNodeProperty(Type type, PropertyInfo property) { - return (type == typeof(LongIdentWithDots) && property.Name == nameof(LongIdentWithDots.id)); - } + private static bool ShouldSkipNodeProperty(Type type, PropertyInfo property) { + return false; + //return (type == typeof(LongIdentWithDots) && property.Name == nameof(LongIdentWithDots.id)); + } - private static bool IsNodeType(Type type) { - return type.Namespace == SyntaxNamespace - && type != typeof(QualifiedNameOfFile) - && type != typeof(SynModuleOrNamespaceKind) - && !(type.Name.StartsWith("SequencePoint")); - } + private static bool IsNodeType(Type type) { + return type.Namespace == SyntaxNamespace + && type != typeof(QualifiedNameOfFile) + && type != typeof(SynModuleOrNamespaceKind) + && !(type.Name.StartsWith("SequencePoint")); + } - private static string? GetTagName(object node) { - return TagNameGetters.Value.TryGetValue(node.GetType(), out var getter) - ? getter.Invoke(node) - : null; - } + private static string? GetTagName(object node) { + return TagNameGetters.Value.TryGetValue(node.GetType(), out var getter) + ? getter.Invoke(node) + : null; + } - private static IReadOnlyDictionary> SlowCompileTagNameGetters() { - var getters = new Dictionary>(); - void SlowCompileAndCollectRecursive(Type astType) { - foreach (var nested in astType.GetNestedTypes()) { - if (nested.Name == "Tags") { - getters.Add(astType, SlowCompileTagNameGetter(astType, nested)); - continue; - } - SlowCompileAndCollectRecursive(nested); + private static IReadOnlyDictionary> SlowCompileTagNameGetters() { + var getters = new Dictionary>(); + void SlowCompileAndCollectRecursive(Type astType) { + foreach (var nested in astType.GetNestedTypes()) { + if (nested.Name == "Tags") { + getters.Add(astType, SlowCompileTagNameGetter(astType, nested)); + continue; } + SlowCompileAndCollectRecursive(nested); } - - foreach (var topLevel in TopLevelAstTypes.Value) { - SlowCompileAndCollectRecursive(topLevel); - } - return getters; } - private static Func SlowCompileTagNameGetter(Type astType, Type tagsType) { - var tagMap = tagsType - .GetFields() - .OrderBy(f => (int)f.GetValue(null)!) - .Select(f => f.Name) - .ToArray(); - var nodeUntyped = Expression.Parameter(typeof(object)); - var tagGetter = Expression.Lambda>( - Expression.Property(Expression.Convert(nodeUntyped, astType), "Tag"), - nodeUntyped - ).Compile(); - return instance => tagMap[tagGetter(instance)]; + foreach (var topLevel in TopLevelAstTypes.Value) { + SlowCompileAndCollectRecursive(topLevel); } + return getters; + } - private static IReadOnlyDictionary> SlowCompileConstValueGetters() { - var getters = new Dictionary>(); - foreach (var type in typeof(SynConst).GetNestedTypes()) { - if (type.BaseType != typeof(SynConst)) - continue; - - var valueProperty = type.GetProperty("Item"); - if (valueProperty == null) - continue; + private static Func SlowCompileTagNameGetter(Type astType, Type tagsType) { + var tagMap = tagsType + .GetFields() + .OrderBy(f => (int)f.GetValue(null)!) + .Select(f => f.Name) + .ToArray(); + var nodeUntyped = Expression.Parameter(typeof(object)); + var tagGetter = Expression.Lambda>( + Expression.Property(Expression.Convert(nodeUntyped, astType), "Tag"), + nodeUntyped + ).Compile(); + return instance => tagMap[tagGetter(instance)]; + } - var toString = valueProperty.PropertyType.GetMethod("ToString", Type.EmptyTypes)!; - var constUntyped = Expression.Parameter(typeof(SynConst)); - getters.Add(type, Expression.Lambda>( - Expression.Call(Expression.Property(Expression.Convert(constUntyped, type), valueProperty), toString), - constUntyped - ).Compile()); - } - return getters; + private static IReadOnlyDictionary> SlowCompileConstValueGetters() { + var getters = new Dictionary>(); + foreach (var type in typeof(SynConst).GetNestedTypes()) { + if (type.BaseType != typeof(SynConst)) + continue; + + var valueProperty = type.GetProperty("Item"); + if (valueProperty == null) + continue; + + var toString = valueProperty.PropertyType.GetMethod("ToString", Type.EmptyTypes)!; + var constUntyped = Expression.Parameter(typeof(SynConst)); + getters.Add(type, Expression.Lambda>( + Expression.Call(Expression.Property(Expression.Convert(constUntyped, type), valueProperty), toString), + constUntyped + ).Compile()); } + return getters; + } - private static IReadOnlyDictionary SlowCollectAstTypeNames() { - var results = new Dictionary(); - void CollectRecusive(IEnumerable astTypes, string parentPrefix) { - foreach (var astType in astTypes) { - var name = parentPrefix + astType.Name; - var prefix = name + "."; - results.Add(astType, name); - CollectRecusive(astType.GetNestedTypes(), prefix); - } + private static IReadOnlyDictionary SlowCollectAstTypeNames() { + var results = new Dictionary(); + void CollectRecusive(IEnumerable astTypes, string parentPrefix) { + foreach (var astType in astTypes) { + var name = parentPrefix + astType.Name; + var prefix = name + "."; + results.Add(astType, name); + CollectRecusive(astType.GetNestedTypes(), prefix); } - - CollectRecusive(TopLevelAstTypes.Value, ""); - return results; } - public IReadOnlyCollection SupportedLanguageNames { get; } = new[] { "F#" }; + CollectRecusive(TopLevelAstTypes.Value, ""); + return results; } + + public IReadOnlyCollection SupportedLanguageNames { get; } = new[] { "F#" }; } \ No newline at end of file diff --git a/source/NetFramework/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs b/source/NetFramework/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs index d309c9763..0881c203e 100644 --- a/source/NetFramework/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs +++ b/source/NetFramework/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs @@ -114,7 +114,10 @@ private bool SlowShouldSkip(PropertyInfo property) { return property.Name == nameof(IOperation.Language) || property.Name == nameof(IOperation.Kind) || property.Name == nameof(IOperation.Parent) + #pragma warning disable CS0618 // Type or member is obsolete || property.Name == nameof(IOperation.Children) + #pragma warning restore CS0618 // Type or member is obsolete + || property.Name == nameof(IOperation.ChildOperations) || property.Name == nameof(IOperation.Syntax) || property.PropertyType.IsAssignableTo() || property.PropertyType.IsAssignableTo>(); diff --git a/source/NetFramework/Server/Decompilation/Internal/IsolatedJitAsmDecompilerCore.cs b/source/NetFramework/Server/Decompilation/Internal/IsolatedJitAsmDecompilerCore.cs index 437cce3f3..26a327332 100644 --- a/source/NetFramework/Server/Decompilation/Internal/IsolatedJitAsmDecompilerCore.cs +++ b/source/NetFramework/Server/Decompilation/Internal/IsolatedJitAsmDecompilerCore.cs @@ -10,7 +10,7 @@ namespace SharpLab.Server.Decompilation.Internal { public static class IsolatedJitAsmDecompilerCore { public static IReadOnlyList JitCompileAndGetMethods(Assembly assembly) { - ValidateStaticConstructors(assembly); + EnsureNoJitSideEffects(assembly); var results = new List(); foreach (var type in assembly.DefinedTypes) { if (type.IsNested) @@ -20,18 +20,25 @@ public static IReadOnlyList JitCompileAndGetMethods(Assembly as return results; } - // This is a security consideration as PrepareMethod calls static ctors - private static void ValidateStaticConstructors(Assembly assembly) { + // This is a security consideration as PrepareMethod calls static ctors and module initializers + private static void EnsureNoJitSideEffects(Assembly assembly) { try { foreach (var type in assembly.DefinedTypes) { foreach (var constructor in type.DeclaredConstructors) { if (constructor.IsStatic) throw new NotSupportedException($"Type {type} has a static constructor, which is not supported by SharpLab JIT decompiler."); } + + foreach (var method in type.DeclaredMethods) { + foreach (var attribute in method.CustomAttributes) { + if (attribute.AttributeType is { Name: "ModuleInitializerAttribute", Namespace: "System.Runtime.CompilerServices" }) + throw new NotSupportedException($"Method {method} is a module initializer, which is not supported by SharpLab JIT decompiler."); + } + } } } catch (ReflectionTypeLoadException ex) { - throw new NotSupportedException("Unable to validate whether code is using static contructors (not supported by SharpLab JIT decompiler).", ex); + throw new NotSupportedException("Unable to validate whether code has static constructors or module initializers (not supported by SharpLab JIT decompiler).", ex); } } diff --git a/source/NetFramework/Server/Decompilation/JitAsmDecompilerBase.cs b/source/NetFramework/Server/Decompilation/JitAsmDecompilerBase.cs index d732f1fb1..105a36818 100644 --- a/source/NetFramework/Server/Decompilation/JitAsmDecompilerBase.cs +++ b/source/NetFramework/Server/Decompilation/JitAsmDecompilerBase.cs @@ -3,239 +3,192 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using JetBrains.Annotations; using Microsoft.Diagnostics.Runtime; -using Microsoft.Diagnostics.Runtime.DacInterface; +using Pidgin; using SharpDisasm; using SharpDisasm.Translators; using SharpLab.Server.Common; using SharpLab.Server.Decompilation.Internal; -namespace SharpLab.Server.Decompilation { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public abstract class JitAsmDecompilerBase : IDecompiler { - public string LanguageName => TargetNames.JitAsm; +namespace SharpLab.Server.Decompilation; - public void Decompile(CompilationStreamPair streams, TextWriter codeWriter) { - Argument.NotNull(nameof(streams), streams); - Argument.NotNull(nameof(codeWriter), codeWriter); +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public abstract class JitAsmDecompilerBase : IDecompiler { + public string LanguageName => TargetNames.JitAsm; - using var resultScope = JitCompileAndGetMethods(streams.AssemblyStream); - using var dataTarget = DataTarget.AttachToProcess(Current.ProcessId, suspend: false); + public void Decompile(CompilationStreamPair streams, TextWriter codeWriter) { + Argument.NotNull(nameof(streams), streams); + Argument.NotNull(nameof(codeWriter), codeWriter); - var currentMethodAddressRef = new Reference(); - var runtime = dataTarget.ClrVersions.Single(v => v.Flavor == ClrFlavor).CreateRuntime(); - var translator = new IntelTranslator { - SymbolResolver = (Instruction instruction, long addr, ref long offset) => - ResolveSymbol(runtime, instruction, addr, currentMethodAddressRef.Value) - }; + using var resultScope = JitCompileAndGetMethods(streams.AssemblyStream); + using var dataTarget = DataTarget.AttachToProcess(Current.ProcessId, suspend: false); - WriteJitInfo(runtime.ClrInfo, codeWriter); - WriteProfilerState(codeWriter); - codeWriter.WriteLine(); + var currentMethodAddressRef = new Reference(); + var runtime = dataTarget.ClrVersions.Single(v => v.Flavor == ClrFlavor).CreateRuntime(); + var translator = new IntelTranslator { + SymbolResolver = (Instruction instruction, long addr, ref long offset) => + ResolveSymbol(runtime, instruction, addr, currentMethodAddressRef.Value) + }; - var architecture = MapArchitecture(runtime.ClrInfo.DacInfo.TargetArchitecture); - foreach (var result in resultScope.Results) { - DisassembleAndWrite(result, runtime, architecture, translator, currentMethodAddressRef, codeWriter); - codeWriter.WriteLine(); - } + WriteJitInfo(runtime.ClrInfo, codeWriter); + WriteProfilerState(codeWriter); + codeWriter.WriteLine(); + + var architecture = MapArchitecture(runtime.DataTarget.DataReader.Architecture); + foreach (var result in resultScope.Results) { + DisassembleAndWrite(result, runtime, architecture, translator, currentMethodAddressRef, codeWriter); + codeWriter.WriteLine(); } + } - protected abstract ClrFlavor ClrFlavor { get; } - protected abstract JitAsmResultScope JitCompileAndGetMethods(MemoryStream assemblyStream); + protected abstract ClrFlavor ClrFlavor { get; } + protected abstract JitAsmResultScope JitCompileAndGetMethods(MemoryStream assemblyStream); - private void WriteJitInfo(ClrInfo clr, TextWriter writer) { - writer.WriteLine( - "; {0:G} CLR {1} on {2}", - clr.Flavor, clr.Version, clr.DacInfo.TargetArchitecture.ToString("G").ToLowerInvariant() - ); - } + private void WriteJitInfo(ClrInfo clr, TextWriter writer) { + writer.WriteLine( + "; {0:G} CLR {1} on {2}", + clr.Flavor, clr.Version, clr.DataTarget.DataReader.Architecture.ToString("G").ToLowerInvariant() + ); + } - private void WriteProfilerState(TextWriter writer) { - if (!ProfilerState.Active) - return; + private void WriteProfilerState(TextWriter writer) { + if (!ProfilerState.Active) + return; - writer.WriteLine("; Note: Running under profiler, which affects JIT assembly in heap allocations."); + writer.WriteLine("; Note: Running under profiler, which affects JIT assembly in heap allocations."); + } + + private static string? ResolveSymbol(ClrRuntime runtime, Instruction instruction, long addr, ulong currentMethodAddress) { + var operand = instruction.Operands.Length > 0 ? instruction.Operands[0] : null; + if (operand?.PtrOffset == 0) { + var lvalue = GetOperandLValue(operand!); + if (lvalue == null) + return $"{operand!.RawValue} ; failed to resolve lval ({operand.Size}), please report at https://github.com/ashmind/SharpLab/issues"; + var baseOffset = instruction.PC - currentMethodAddress; + return $"L{baseOffset + lvalue:x4}"; } - private static string? ResolveSymbol(ClrRuntime runtime, Instruction instruction, long addr, ulong currentMethodAddress) { - var operand = instruction.Operands.Length > 0 ? instruction.Operands[0] : null; - if (operand?.PtrOffset == 0) { - var lvalue = GetOperandLValue(operand!); - if (lvalue == null) - return $"{operand!.RawValue} ; failed to resolve lval ({operand.Size}), please report at https://github.com/ashmind/SharpLab/issues"; - var baseOffset = instruction.PC - currentMethodAddress; - return $"L{baseOffset + lvalue:x4}"; - } + return runtime.GetMethodByInstructionPointer(unchecked((ulong)addr))?.Signature; + } - return runtime.GetMethodByInstructionPointer(unchecked((ulong)addr))?.Signature; + private static ulong? GetOperandLValue(Operand operand) { + switch (operand.Size) { + case 8: return (ulong)operand.LvalSByte; + case 16: return (ulong)operand.LvalSWord; + case 32: return (ulong)operand.LvalSDWord; + default: return null; } + } - private static ulong? GetOperandLValue(Operand operand) { - switch (operand.Size) { - case 8: return (ulong)operand.LvalSByte; - case 16: return (ulong)operand.LvalSWord; - case 32: return (ulong)operand.LvalSDWord; - default: return null; - } + private void DisassembleAndWrite(MethodJitResult result, ClrRuntime runtime, ArchitectureMode architecture, Translator translator, Reference methodAddressRef, TextWriter writer) { + void WriteSignatureFromClrMethod() { + var signature = runtime.GetMethodByHandle(unchecked((ulong)result.Handle.ToInt64()))?.Signature; + WriteSignature(signature); } - private void DisassembleAndWrite(MethodJitResult result, ClrRuntime runtime, ArchitectureMode architecture, Translator translator, Reference methodAddressRef, TextWriter writer) { - void WriteSignatureFromClrMethod() { - var signature = runtime.GetMethodByHandle(unchecked((ulong)result.Handle.ToInt64()))?.Signature; - WriteSignature(signature); + void WriteSignature(string? signature) { + if (signature != null) { + writer.WriteLine(signature); } - - void WriteSignature(string? signature) { - if (signature != null) { - writer.WriteLine(signature); - } - else { - writer.WriteLine("Unknown (0x{0:X})", (ulong)result.Handle.ToInt64()); - writer.WriteLine(" ; Method signature was not found -- please report this issue."); - } - } - - switch (result.Status) { - case MethodJitStatus.IgnoredPInvoke: - WriteSignatureFromClrMethod(); - writer.WriteLine(" ; Cannot produce JIT assembly for a P/Invoke method."); - return; - case MethodJitStatus.IgnoredRuntime: - WriteSignatureFromClrMethod(); - writer.WriteLine(" ; Cannot produce JIT assembly for runtime-implemented method."); - return; - case MethodJitStatus.IgnoredOpenGenericWithNoAttribute: - WriteSignatureFromClrMethod(); - writer.WriteLine(" ; Open generics cannot be JIT-compiled."); - writer.WriteLine(" ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types."); - writer.WriteLine(" ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }."); - return; + else { + writer.WriteLine("Unknown (0x{0:X})", (ulong)result.Handle.ToInt64()); + writer.WriteLine(" ; Method signature was not found -- please report this issue."); } + } - if (FindJitCompiledMethod(runtime, result) is not {} method) { + switch (result.Status) { + case MethodJitStatus.IgnoredPInvoke: WriteSignatureFromClrMethod(); - if (result.Status == MethodJitStatus.SuccessGeneric) { - writer.WriteLine(" ; Failed to find JIT output for generic method (reference types?)."); - writer.WriteLine(" ; If you know a solution, please comment at https://github.com/ashmind/SharpLab/issues/99."); - return; - } - - writer.WriteLine(" ; Failed to find JIT output — please report at https://github.com/ashmind/SharpLab/issues."); + writer.WriteLine(" ; Cannot produce JIT assembly for a P/Invoke method."); + return; + case MethodJitStatus.IgnoredRuntime: + WriteSignatureFromClrMethod(); + writer.WriteLine(" ; Cannot produce JIT assembly for runtime-implemented method."); + return; + case MethodJitStatus.IgnoredOpenGenericWithNoAttribute: + WriteSignatureFromClrMethod(); + writer.WriteLine(" ; Open generics cannot be JIT-compiled."); + writer.WriteLine(" ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types."); + writer.WriteLine(" ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }."); return; - } - - WriteSignature(method.Signature); - var methodAddress = method.MethodAddress; - methodAddressRef.Value = methodAddress; - using (var disasm = new Disassembler(new IntPtr(unchecked((long)methodAddress)), (int)method.MethodSize, architecture, methodAddress)) { - foreach (var instruction in disasm.Disassemble()) { - writer.Write(" L"); - writer.Write((instruction.Offset - methodAddress).ToString("x4")); - writer.Write(": "); - writer.WriteLine(translator.Translate(instruction)); - } - } - } - - private ClrMethodData? FindJitCompiledMethod(ClrRuntime runtime, MethodJitResult result) { - var sos = runtime.DacLibrary.SOSDacInterface; - - var methodDescAddress = unchecked((ulong)result.Handle.ToInt64()); - if (!sos.GetMethodDescData(methodDescAddress, 0, out var methodDesc)) - return null; - - return GetJitCompiledMethodByMethodDescIfValid(sos, methodDesc) - ?? FindJitCompiledMethodInMethodTable(sos, methodDesc); } - private ClrMethodData? GetJitCompiledMethodByMethodDescIfValid(SOSDac sos, MethodDescData methodDesc) { - // https://github.com/microsoft/clrmd/issues/935 - var codeHeaderAddress = methodDesc.HasNativeCode != 0 - ? (ulong)methodDesc.NativeCodeAddr - : sos.GetMethodTableSlot(methodDesc.MethodTable, methodDesc.SlotNumber); - - if (codeHeaderAddress == unchecked((ulong)-1)) - return null; - - if (!sos.GetCodeHeaderData(codeHeaderAddress, out var codeHeader)) - return null; - - return GetJitCompiledMethodByCodeHeaderIfValid(sos, codeHeader); + if (FindJitCompiledMethod(runtime, result) is not {} method) { + WriteSignatureFromClrMethod(); + writer.WriteLine(" ; Failed to find JIT output. This might appear more frequently than before due to a library update."); + writer.WriteLine(" ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress."); + return; } - private ClrMethodData? GetJitCompiledMethodByCodeHeaderIfValid(SOSDac sos, CodeHeaderData codeHeader) { - if (codeHeader.MethodStart.Value == -1 || codeHeader.HotRegionSize == 0) - return null; - - return new( - sos.GetMethodDescName(codeHeader.MethodDesc), - unchecked((ulong)codeHeader.MethodStart.Value), - codeHeader.HotRegionSize - ); + WriteSignature(method.Signature); + var methodAddress = method.MethodAddress; + methodAddressRef.Value = methodAddress; + using (var disasm = new Disassembler(new IntPtr(unchecked((long)methodAddress)), (int)method.MethodSize, architecture, methodAddress)) { + foreach (var instruction in disasm.Disassemble()) { + writer.Write(" L"); + writer.Write((instruction.Offset - methodAddress).ToString("x4")); + writer.Write(": "); + writer.WriteLine(translator.Translate(instruction)); + } } + } - private ClrMethodData? FindJitCompiledMethodInMethodTable(SOSDac sos, MethodDescData originalMethodDesc) { - // I can't really explain this, but it seems that some methods - // are present multiple times in the same type -- one compiled - // and one not compiled. - - if (!sos.GetMethodTableData(originalMethodDesc.MethodTable, out var methodTable)) - return null; + private ClrMethodData? FindJitCompiledMethod(ClrRuntime runtime, MethodJitResult result) { + lock (runtime) + runtime.FlushCachedData(); - ClrMethodData? methodData = null; - for (var i = 0u; i < methodTable.NumMethods; i++) { - if (i == originalMethodDesc.SlotNumber) - continue; + var methodDescAddress = unchecked((ulong)result.Handle.ToInt64()); + if (runtime.GetMethodByHandle(methodDescAddress) is not { } method) + return null; - var slot = sos.GetMethodTableSlot(originalMethodDesc.MethodTable, i); - if (!sos.GetCodeHeaderData(slot, out var candidateCodeHeader)) - continue; + if (method.CompilationType == MethodCompilationType.None) + return null; - if (!sos.GetMethodDescData(candidateCodeHeader.MethodDesc, 0, out var candidateMethodDesc)) - continue; + if (method.NativeCode == 0) + return null; - if (candidateMethodDesc.MDToken != originalMethodDesc.MDToken) - continue; + if (method.HotColdInfo.HotSize == 0) + return null; - methodData = GetJitCompiledMethodByCodeHeaderIfValid(sos, candidateCodeHeader); - if (methodData != null) - break; - } - return methodData; - } + return new( + method.Signature, + method.NativeCode, + method.HotColdInfo.HotSize + ); + } - private ArchitectureMode MapArchitecture(Architecture architecture) => architecture switch { - Architecture.Amd64 => ArchitectureMode.x86_64, - Architecture.X86 => ArchitectureMode.x86_32, - // ReSharper disable once HeapView.BoxingAllocation - // ReSharper disable once HeapView.ObjectAllocation.Evident - _ => throw new Exception($"Unsupported architecture mode {architecture}."), - }; + private ArchitectureMode MapArchitecture(Architecture architecture) => architecture switch { + Architecture.X64 => ArchitectureMode.x86_64, + Architecture.X86 => ArchitectureMode.x86_32, + // ReSharper disable once HeapView.BoxingAllocation + // ReSharper disable once HeapView.ObjectAllocation.Evident + _ => throw new Exception($"Unsupported architecture mode {architecture}."), + }; + + private class Reference { + #pragma warning disable CS8618 // Non-nullable field is uninitialized. + public T Value { get; set; } + #pragma warning restore CS8618 // Non-nullable field is uninitialized. + } - private class Reference { - #pragma warning disable CS8618 // Non-nullable field is uninitialized. - public T Value { get; set; } - #pragma warning restore CS8618 // Non-nullable field is uninitialized. + private static class Remote { + public static IReadOnlyList GetCompiledMethods(byte[] assemblyBytes) { + var assembly = Assembly.Load(assemblyBytes); + return IsolatedJitAsmDecompilerCore.JitCompileAndGetMethods(assembly); } + } - private static class Remote { - public static IReadOnlyList GetCompiledMethods(byte[] assemblyBytes) { - var assembly = Assembly.Load(assemblyBytes); - return IsolatedJitAsmDecompilerCore.JitCompileAndGetMethods(assembly); - } + private readonly struct ClrMethodData { + public ClrMethodData(string? signature, ulong methodAddress, uint methodSize) { + Signature = signature; + MethodAddress = methodAddress; + MethodSize = methodSize; } - private readonly struct ClrMethodData { - public ClrMethodData(string? signature, ulong methodAddress, uint methodSize) { - Signature = signature; - MethodAddress = methodAddress; - MethodSize = methodSize; - } - - public string? Signature { get; } - public ulong MethodAddress { get; } - public uint MethodSize { get; } - } + public string? Signature { get; } + public ulong MethodAddress { get; } + public uint MethodSize { get; } } } \ No newline at end of file diff --git a/source/NetFramework/Server/Execution/ExecutionModule.cs b/source/NetFramework/Server/Execution/ExecutionModule.cs index 5755bdc85..a079649b1 100644 --- a/source/NetFramework/Server/Execution/ExecutionModule.cs +++ b/source/NetFramework/Server/Execution/ExecutionModule.cs @@ -3,33 +3,29 @@ using SharpLab.Server.Execution.Internal; using SharpLab.Server.Execution.Unbreakable; -namespace SharpLab.Server.Execution { - [UsedImplicitly] - public class ExecutionModule : Module { - protected override void Load(ContainerBuilder builder) { - builder.RegisterInstance(ApiPolicySetup.CreatePolicy()) - .AsSelf() - .SingleInstance(); +namespace SharpLab.Server.Execution; - builder.RegisterType() - .AsSelf() - .SingleInstance(); +[UsedImplicitly] +public class ExecutionModule : Module { + protected override void Load(ContainerBuilder builder) { + builder.RegisterInstance(ApiPolicySetup.CreatePolicy()) + .AsSelf() + .SingleInstance(); - builder.RegisterType() - .As() - .SingleInstance(); + builder.RegisterType() + .AsSelf() + .SingleInstance(); - builder.RegisterType() - .As() - .SingleInstance(); + builder.RegisterType() + .As() + .SingleInstance(); - builder.RegisterType() - .As() - .SingleInstance(); + builder.RegisterType() + .As() + .SingleInstance(); - builder.RegisterType() - .As() - .SingleInstance(); - } + builder.RegisterType() + .As() + .SingleInstance(); } } diff --git a/source/NetFramework/Server/Execution/Internal/FSharpEntryPointRewriter.cs b/source/NetFramework/Server/Execution/Internal/FSharpEntryPointRewriter.cs deleted file mode 100644 index 80854759c..000000000 --- a/source/NetFramework/Server/Execution/Internal/FSharpEntryPointRewriter.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Microsoft.FSharp.Core; -using MirrorSharp.Advanced; -using MirrorSharp.FSharp.Advanced; -using Mono.Cecil; - -namespace SharpLab.Server.Execution.Internal { - // There are some weird problems when I try to compile F# code as an exe (e.g. it tries to - // do filesystem operations without using the virtual filesystem), so instead I compile - // it as a library and then fake the entry point. - public class FSharpEntryPointRewriter : IAssemblyRewriter { - public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { - if (!session.IsFSharp()) - return; - - if (assembly.EntryPoint != null) - return; - - var (entryPoint, isStaticConstructor) = FindBestEntryPointCandidate(assembly); - if (entryPoint == null) - return; - - if (isStaticConstructor) { - entryPoint.Attributes &= ~MethodAttributes.SpecialName & ~MethodAttributes.RTSpecialName; - entryPoint.Name = "cctor_rewritten_to_method_by_sharplab"; - } - assembly.EntryPoint = entryPoint; - } - - private (MethodDefinition? method, bool isStaticConstructor) FindBestEntryPointCandidate(AssemblyDefinition assembly) { - // First priority -- explicit [] - // Second priority -- top level code (gets compiled into a static ctor) - - MethodDefinition? startup = null; - foreach (var type in assembly.MainModule.Types) { - if (type.Namespace == "" && type.Name == "$_" && type.HasMethods) { - foreach (var method in type.Methods) { - if (method.IsConstructor && method.IsStatic) { - startup = method; - break; - } - } - continue; - } - - if (type.Namespace == "" && type.Name == "_" && type.HasMethods) { - foreach (var method in type.Methods) { - if (HasEntryPointAttribute(method)) - return (method, false); - } - } - } - - return (startup, startup != null); - } - - private bool HasEntryPointAttribute(MethodDefinition method) { - if (!method.HasCustomAttributes) - return false; - - foreach (var attribute in method.CustomAttributes) { - if (attribute.AttributeType.Namespace == "Microsoft.FSharp.Core" && attribute.AttributeType.Name == nameof(EntryPointAttribute)) - return true; - } - return false; - } - } -} \ No newline at end of file diff --git a/source/NetFramework/Server/Execution/Internal/FlowReportingRewriter.cs b/source/NetFramework/Server/Execution/Internal/FlowReportingRewriter.cs index d1a1730fd..7e484230e 100644 --- a/source/NetFramework/Server/Execution/Internal/FlowReportingRewriter.cs +++ b/source/NetFramework/Server/Execution/Internal/FlowReportingRewriter.cs @@ -7,323 +7,323 @@ using SharpLab.Runtime.Internal; using SharpLab.Server.Common; -namespace SharpLab.Server.Execution.Internal { - public class FlowReportingRewriter : IAssemblyRewriter { - private const int HiddenLine = 0xFEEFEE; - - private static readonly MethodInfo ReportLineStartMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportLineStart))!; - private static readonly MethodInfo ReportValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportValue))!; - private static readonly MethodInfo ReportRefValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportRefValue))!; - private static readonly MethodInfo ReportSpanValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportSpanValue))!; - private static readonly MethodInfo ReportRefSpanValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportRefSpanValue))!; - private static readonly MethodInfo ReportReadOnlySpanValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportReadOnlySpanValue))!; - private static readonly MethodInfo ReportRefReadOnlySpanValueMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportRefReadOnlySpanValue))!; - private static readonly MethodInfo ReportExceptionMethod = - typeof(Flow).GetMethod(nameof(Flow.ReportException))!; - - private readonly IReadOnlyDictionary _languages; - - public FlowReportingRewriter(IReadOnlyList languages) { - _languages = languages.ToDictionary(l => l.LanguageName); - } - - public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { - foreach (var module in assembly.Modules) { - foreach (var type in module.Types) { - if (HasFlowSupressingCalls(type)) - return; - } - } +namespace SharpLab.Server.Execution.Internal; + +public class FlowReportingRewriter : IAssemblyRewriter { + private const int HiddenLine = 0xFEEFEE; + + private static readonly MethodInfo ReportLineStartMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportLineStart))!; + private static readonly MethodInfo ReportValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportValue))!; + private static readonly MethodInfo ReportRefValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefValue))!; + private static readonly MethodInfo ReportSpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportSpanValue))!; + private static readonly MethodInfo ReportRefSpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefSpanValue))!; + private static readonly MethodInfo ReportReadOnlySpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportReadOnlySpanValue))!; + private static readonly MethodInfo ReportRefReadOnlySpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefReadOnlySpanValue))!; + private static readonly MethodInfo ReportExceptionMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportException))!; + + private readonly IReadOnlyDictionary _languages; + + public FlowReportingRewriter(IReadOnlyList languages) { + _languages = languages.ToDictionary(l => l.LanguageName); + } - foreach (var module in assembly.Modules) { - var flow = new ReportMethods { - ReportLineStart = module.ImportReference(ReportLineStartMethod), - ReportValue = module.ImportReference(ReportValueMethod), - ReportRefValue = module.ImportReference(ReportRefValueMethod), - ReportSpanValue = module.ImportReference(ReportSpanValueMethod), - ReportRefSpanValue = module.ImportReference(ReportRefSpanValueMethod), - ReportReadOnlySpanValue = module.ImportReference(ReportReadOnlySpanValueMethod), - ReportRefReadOnlySpanValue = module.ImportReference(ReportRefReadOnlySpanValueMethod), - ReportException = module.ImportReference(ReportExceptionMethod), - }; - foreach (var type in module.Types) { - Rewrite(type, flow, session); - } + public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { + foreach (var module in assembly.Modules) { + foreach (var type in module.Types) { + if (HasFlowSupressingCalls(type)) + return; } } - private bool HasFlowSupressingCalls(TypeDefinition type) { - foreach (var method in type.Methods) { - if (!method.HasBody || method.Body.Instructions.Count == 0) - continue; - foreach (var instruction in method.Body.Instructions) { - if (instruction.OpCode.FlowControl == FlowControl.Call && IsFlowSuppressing((MethodReference)instruction.Operand)) - return true; - } + foreach (var module in assembly.Modules) { + var flow = new ReportMethods { + ReportLineStart = module.ImportReference(ReportLineStartMethod), + ReportValue = module.ImportReference(ReportValueMethod), + ReportRefValue = module.ImportReference(ReportRefValueMethod), + ReportSpanValue = module.ImportReference(ReportSpanValueMethod), + ReportRefSpanValue = module.ImportReference(ReportRefSpanValueMethod), + ReportReadOnlySpanValue = module.ImportReference(ReportReadOnlySpanValueMethod), + ReportRefReadOnlySpanValue = module.ImportReference(ReportRefReadOnlySpanValueMethod), + ReportException = module.ImportReference(ReportExceptionMethod), + }; + foreach (var type in module.Types) { + Rewrite(type, flow, session); } + } + } - foreach (var nested in type.NestedTypes) { - if (HasFlowSupressingCalls(nested)) + private bool HasFlowSupressingCalls(TypeDefinition type) { + foreach (var method in type.Methods) { + if (!method.HasBody || method.Body.Instructions.Count == 0) + continue; + foreach (var instruction in method.Body.Instructions) { + if (instruction.OpCode.FlowControl == FlowControl.Call && IsFlowSuppressing((MethodReference)instruction.Operand)) return true; } - - return false; } - private bool IsFlowSuppressing(MethodReference callee) { - return callee.Name == nameof(Inspect.Allocations) - && callee.DeclaringType.Name == nameof(Inspect); + foreach (var nested in type.NestedTypes) { + if (HasFlowSupressingCalls(nested)) + return true; } - private void Rewrite(TypeDefinition type, ReportMethods flow, IWorkSession session) { - foreach (var method in type.Methods) { - Rewrite(method, flow, session); - } + return false; + } - foreach (var nested in type.NestedTypes) { - Rewrite(nested, flow, session); - } - } + private bool IsFlowSuppressing(MethodReference callee) { + return callee.Name == nameof(Inspect.Allocations) + && callee.DeclaringType.Name == nameof(Inspect); + } - private void Rewrite(MethodDefinition method, ReportMethods flow, IWorkSession session) { - if (!method.HasBody || method.Body.Instructions.Count == 0) - return; - - var il = method.Body.GetILProcessor(); - var instructions = il.Body.Instructions; - var lastLine = (int?)null; - for (var i = 0; i < instructions.Count; i++) { - var instruction = instructions[i]; - var sequencePoint = method.DebugInformation?.GetSequencePoint(instruction); - var hasSequencePoint = sequencePoint != null && sequencePoint.StartLine != HiddenLine; - if (!hasSequencePoint && lastLine == null) - continue; - - if (hasSequencePoint && sequencePoint!.StartLine != lastLine) { - if (i == 0) - TryInsertReportMethodArguments(il, instruction, sequencePoint, method, flow, session, ref i); - - il.InsertBeforeAndRetargetAll(instruction, il.CreateLdcI4Best(sequencePoint.StartLine)); - il.InsertBefore(instruction, il.CreateCall(flow.ReportLineStart)); - i += 2; - lastLine = sequencePoint.StartLine; - } - - var valueOrNull = GetValueToReport(instruction, il, session); - if (valueOrNull == null) - continue; - - var value = valueOrNull.Value; - InsertReportValue( - il, instruction, - il.Create(OpCodes.Dup), value.type, value.name, - sequencePoint?.StartLine ?? lastLine ?? Flow.UnknownLineNumber, - flow, ref i - ); - } + private void Rewrite(TypeDefinition type, ReportMethods flow, IWorkSession session) { + foreach (var method in type.Methods) { + Rewrite(method, flow, session); + } - RewriteExceptionHandlers(il, flow); + foreach (var nested in type.NestedTypes) { + Rewrite(nested, flow, session); } + } - private void TryInsertReportMethodArguments(ILProcessor il, Instruction instruction, SequencePoint sequencePoint, MethodDefinition method, ReportMethods flow, IWorkSession session, ref int index) { - if (!method.HasParameters) - return; - - var parameterLines = _languages[session.LanguageName] - .GetMethodParameterLines(session, sequencePoint.StartLine, sequencePoint.StartColumn); - - if (parameterLines.Length == 0) - return; - - // Note: method parameter lines are unreliable and can potentially return - // wrong lines if nested method syntax is unrecognized and code matches it - // to the containing method. That is acceptable, as long as parameter count - // mismatch does not crash things -> so check length here. - if (parameterLines.Length != method.Parameters.Count) - return; - - foreach (var parameter in method.Parameters) { - if (parameter.IsOut) - continue; - - InsertReportValue( - il, instruction, - il.CreateLdargBest(parameter), parameter.ParameterType, parameter.Name, - parameterLines[parameter.Index], flow, - ref index - ); + private void Rewrite(MethodDefinition method, ReportMethods flow, IWorkSession session) { + if (!method.HasBody || method.Body.Instructions.Count == 0) + return; + + var il = method.Body.GetILProcessor(); + var instructions = il.Body.Instructions; + var lastLine = (int?)null; + for (var i = 0; i < instructions.Count; i++) { + var instruction = instructions[i]; + var sequencePoint = method.DebugInformation?.GetSequencePoint(instruction); + var hasSequencePoint = sequencePoint != null && sequencePoint.StartLine != HiddenLine; + if (!hasSequencePoint && lastLine == null) + continue; + + if (hasSequencePoint && sequencePoint!.StartLine != lastLine) { + if (i == 0) + TryInsertReportMethodArguments(il, instruction, sequencePoint, method, flow, session, ref i); + + il.InsertBeforeAndRetargetAll(instruction, il.CreateLdcI4Best(sequencePoint.StartLine)); + il.InsertBefore(instruction, il.CreateCall(flow.ReportLineStart)); + i += 2; + lastLine = sequencePoint.StartLine; } + + var valueOrNull = GetValueToReport(instruction, il, session); + if (valueOrNull == null) + continue; + + var value = valueOrNull.Value; + InsertReportValue( + il, instruction, + il.Create(OpCodes.Dup), value.type, value.name, + sequencePoint?.StartLine ?? lastLine ?? Flow.UnknownLineNumber, + flow, ref i + ); } - private (string name, TypeReference type)? GetValueToReport(Instruction instruction, ILProcessor il, IWorkSession session) { - var localIndex = GetIndexIfStloc(instruction); - if (localIndex != null) { - var variable = il.Body.Variables[localIndex.Value]; - var symbols = il.Body.Method.DebugInformation; - if (symbols == null || !symbols.TryGetName(variable, out var variableName)) - return null; + RewriteExceptionHandlers(il, flow); + } - return (variableName, variable.VariableType); - } + private void TryInsertReportMethodArguments(ILProcessor il, Instruction instruction, SequencePoint sequencePoint, MethodDefinition method, ReportMethods flow, IWorkSession session, ref int index) { + if (!method.HasParameters) + return; + + var parameterLines = _languages[session.LanguageName] + .GetMethodParameterLines(session, sequencePoint.StartLine, sequencePoint.StartColumn); + + if (parameterLines.Length == 0) + return; + + // Note: method parameter lines are unreliable and can potentially return + // wrong lines if nested method syntax is unrecognized and code matches it + // to the containing method. That is acceptable, as long as parameter count + // mismatch does not crash things -> so check length here. + if (parameterLines.Length != method.Parameters.Count) + return; + + foreach (var parameter in method.Parameters) { + if (parameter.IsOut) + continue; + + InsertReportValue( + il, instruction, + il.CreateLdargBest(parameter), parameter.ParameterType, parameter.Name, + parameterLines[parameter.Index], flow, + ref index + ); + } + } - if (instruction.OpCode.Code == Code.Ret) { - if (instruction.Previous?.Previous?.OpCode.Code == Code.Tail) - return null; - var returnType = il.Body.Method.ReturnType; - if (returnType.IsVoid()) - return null; - return ("return", returnType); - } + private (string name, TypeReference type)? GetValueToReport(Instruction instruction, ILProcessor il, IWorkSession session) { + var localIndex = GetIndexIfStloc(instruction); + if (localIndex != null) { + var variable = il.Body.Variables[localIndex.Value]; + var symbols = il.Body.Method.DebugInformation; + if (symbols == null || !symbols.TryGetName(variable, out var variableName)) + return null; - return null; + return (variableName, variable.VariableType); } - private void InsertReportValue( - ILProcessor il, - Instruction instruction, - Instruction getValue, - TypeReference valueType, - string valueName, - int line, - ReportMethods flow, - ref int index - ) { - il.InsertBefore(instruction, getValue); - il.InsertBefore(instruction, valueName != null ? il.Create(OpCodes.Ldstr, valueName) : il.Create(OpCodes.Ldnull)); - il.InsertBefore(instruction, il.CreateLdcI4Best(line)); - - if (valueType is RequiredModifierType requiredType) - valueType = requiredType.ElementType; // not the same as GetElementType() which unwraps nested ref-types etc - - var report = PrepareReportValue(valueType, flow.ReportValue, flow.ReportSpanValue, flow.ReportReadOnlySpanValue); - if (valueType is ByReferenceType byRef) - report = PrepareReportValue(byRef.ElementType, flow.ReportRefValue, flow.ReportRefSpanValue, flow.ReportRefReadOnlySpanValue); - - il.InsertBefore(instruction, il.CreateCall(report)); - index += 4; + if (instruction.OpCode.Code == Code.Ret) { + if (instruction.Previous?.Previous?.OpCode.Code == Code.Tail) + return null; + var returnType = il.Body.Method.ReturnType; + if (returnType.IsVoid()) + return null; + return ("return", returnType); } - private GenericInstanceMethod PrepareReportValue(TypeReference valueType, MethodReference reportAnyNonSpan, MethodReference reportSpan, MethodReference reportReadOnlySpan) { - if (valueType is GenericInstanceType generic) { - if (generic.ElementType.FullName == "System.Span`1") - return new GenericInstanceMethod(reportSpan) { GenericArguments = { generic.GenericArguments[0] } }; - if (generic.ElementType.FullName == "System.ReadOnlySpan`1") - return new GenericInstanceMethod(reportReadOnlySpan) { GenericArguments = { generic.GenericArguments[0] } }; - } + return null; + } - return new GenericInstanceMethod(reportAnyNonSpan) { GenericArguments = { valueType } }; + private void InsertReportValue( + ILProcessor il, + Instruction instruction, + Instruction getValue, + TypeReference valueType, + string valueName, + int line, + ReportMethods flow, + ref int index + ) { + il.InsertBefore(instruction, getValue); + il.InsertBefore(instruction, valueName != null ? il.Create(OpCodes.Ldstr, valueName) : il.Create(OpCodes.Ldnull)); + il.InsertBefore(instruction, il.CreateLdcI4Best(line)); + + if (valueType is RequiredModifierType requiredType) + valueType = requiredType.ElementType; // not the same as GetElementType() which unwraps nested ref-types etc + + var report = PrepareReportValue(valueType, flow.ReportValue, flow.ReportSpanValue, flow.ReportReadOnlySpanValue); + if (valueType is ByReferenceType byRef) + report = PrepareReportValue(byRef.ElementType, flow.ReportRefValue, flow.ReportRefSpanValue, flow.ReportRefReadOnlySpanValue); + + il.InsertBefore(instruction, il.CreateCall(report)); + index += 4; + } + + private GenericInstanceMethod PrepareReportValue(TypeReference valueType, MethodReference reportAnyNonSpan, MethodReference reportSpan, MethodReference reportReadOnlySpan) { + if (valueType is GenericInstanceType generic) { + if (generic.ElementType.FullName == "System.Span`1") + return new GenericInstanceMethod(reportSpan) { GenericArguments = { generic.GenericArguments[0] } }; + if (generic.ElementType.FullName == "System.ReadOnlySpan`1") + return new GenericInstanceMethod(reportReadOnlySpan) { GenericArguments = { generic.GenericArguments[0] } }; } - private void RewriteExceptionHandlers(ILProcessor il, ReportMethods flow) { - if (!il.Body.HasExceptionHandlers) - return; - - var handlers = il.Body.ExceptionHandlers; - for (var i = 0; i < handlers.Count; i++) { - switch (handlers[i].HandlerType) { - case ExceptionHandlerType.Catch: - RewriteCatch(handlers[i].HandlerStart, il, flow); - break; - - case ExceptionHandlerType.Filter: - RewriteCatch(handlers[i].FilterStart, il, flow); - break; - - case ExceptionHandlerType.Finally: - RewriteFinally(handlers[i], ref i, il, flow); - break; - } + return new GenericInstanceMethod(reportAnyNonSpan) { GenericArguments = { valueType } }; + } + + private void RewriteExceptionHandlers(ILProcessor il, ReportMethods flow) { + if (!il.Body.HasExceptionHandlers) + return; + + var handlers = il.Body.ExceptionHandlers; + for (var i = 0; i < handlers.Count; i++) { + switch (handlers[i].HandlerType) { + case ExceptionHandlerType.Catch: + RewriteCatch(handlers[i].HandlerStart, il, flow); + break; + + case ExceptionHandlerType.Filter: + RewriteCatch(handlers[i].FilterStart, il, flow); + break; + + case ExceptionHandlerType.Finally: + RewriteFinally(handlers[i], ref i, il, flow); + break; } } + } - private void RewriteCatch(Instruction start, ILProcessor il, ReportMethods flow) { - il.InsertBeforeAndRetargetAll(start, il.Create(OpCodes.Dup)); - il.InsertBefore(start, il.CreateCall(flow.ReportException)); - } + private void RewriteCatch(Instruction start, ILProcessor il, ReportMethods flow) { + il.InsertBeforeAndRetargetAll(start, il.Create(OpCodes.Dup)); + il.InsertBefore(start, il.CreateCall(flow.ReportException)); + } - private void RewriteFinally(ExceptionHandler handler, ref int handlerIndex, ILProcessor il, ReportMethods flow) { - // for try/finally, the only thing we can do is to - // wrap internals of try into a new try+filter+catch - var outerTryLeave = handler.TryEnd.Previous; - if (!outerTryLeave.OpCode.Code.IsLeave()) { - // in some cases (e.g. exception throw) outer handler does - // not end with `leave` -- but we do need it once we wrap - // that throw - - // if the handler is the last thing in the method - if (handler.HandlerEnd == null) - { - var finalReturn = il.Create(OpCodes.Ret); - il.Append(finalReturn); - handler.HandlerEnd = finalReturn; - } - - outerTryLeave = il.Create(OpCodes.Leave, handler.HandlerEnd); - il.InsertBefore(handler.TryEnd, outerTryLeave); + private void RewriteFinally(ExceptionHandler handler, ref int handlerIndex, ILProcessor il, ReportMethods flow) { + // for try/finally, the only thing we can do is to + // wrap internals of try into a new try+filter+catch + var outerTryLeave = handler.TryEnd.Previous; + if (!outerTryLeave.OpCode.Code.IsLeave()) { + // in some cases (e.g. exception throw) outer handler does + // not end with `leave` -- but we do need it once we wrap + // that throw + + // if the handler is the last thing in the method + if (handler.HandlerEnd == null) + { + var finalReturn = il.Create(OpCodes.Ret); + il.Append(finalReturn); + handler.HandlerEnd = finalReturn; } - var innerTryLeave = il.Create(OpCodes.Leave_S, outerTryLeave); - var reportCall = il.CreateCall(flow.ReportException); - var catchHandler = il.Create(OpCodes.Pop); + outerTryLeave = il.Create(OpCodes.Leave, handler.HandlerEnd); + il.InsertBefore(handler.TryEnd, outerTryLeave); + } - il.InsertBeforeAndRetargetAll(outerTryLeave, innerTryLeave); - il.InsertBefore(outerTryLeave, reportCall); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Ldc_I4_0)); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Endfilter)); - il.InsertBefore(outerTryLeave, catchHandler); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Leave_S, outerTryLeave)); + var innerTryLeave = il.Create(OpCodes.Leave_S, outerTryLeave); + var reportCall = il.CreateCall(flow.ReportException); + var catchHandler = il.Create(OpCodes.Pop); - for (var i = 0; i < handlerIndex; i++) { - il.Body.ExceptionHandlers[i].RetargetAll(outerTryLeave.Next, innerTryLeave.Next); - } + il.InsertBeforeAndRetargetAll(outerTryLeave, innerTryLeave); + il.InsertBefore(outerTryLeave, reportCall); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Ldc_I4_0)); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Endfilter)); + il.InsertBefore(outerTryLeave, catchHandler); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Leave_S, outerTryLeave)); - il.Body.ExceptionHandlers.Insert(handlerIndex, new ExceptionHandler(ExceptionHandlerType.Filter) { - TryStart = handler.TryStart, - TryEnd = reportCall, - FilterStart = reportCall, - HandlerStart = catchHandler, - HandlerEnd = outerTryLeave - }); - handlerIndex += 1; + for (var i = 0; i < handlerIndex; i++) { + il.Body.ExceptionHandlers[i].RetargetAll(outerTryLeave.Next, innerTryLeave.Next); } - private void InsertAfter(ILProcessor il, ref Instruction target, ref int index, Instruction instruction) { - il.InsertAfter(target, instruction); - target = instruction; - index += 1; - } + il.Body.ExceptionHandlers.Insert(handlerIndex, new ExceptionHandler(ExceptionHandlerType.Filter) { + TryStart = handler.TryStart, + TryEnd = reportCall, + FilterStart = reportCall, + HandlerStart = catchHandler, + HandlerEnd = outerTryLeave + }); + handlerIndex += 1; + } - private int? GetIndexIfStloc(Instruction instruction) { - switch (instruction.OpCode.Code) { - case Code.Stloc_0: return 0; - case Code.Stloc_1: return 1; - case Code.Stloc_2: return 2; - case Code.Stloc_3: return 3; + private void InsertAfter(ILProcessor il, ref Instruction target, ref int index, Instruction instruction) { + il.InsertAfter(target, instruction); + target = instruction; + index += 1; + } - case Code.Stloc_S: - case Code.Stloc: - return ((VariableReference)instruction.Operand).Index; + private int? GetIndexIfStloc(Instruction instruction) { + switch (instruction.OpCode.Code) { + case Code.Stloc_0: return 0; + case Code.Stloc_1: return 1; + case Code.Stloc_2: return 2; + case Code.Stloc_3: return 3; - default: return null; - } - } + case Code.Stloc_S: + case Code.Stloc: + return ((VariableReference)instruction.Operand).Index; - private struct ReportMethods { - public MethodReference ReportLineStart { get; set; } - public MethodReference ReportValue { get; set; } - public MethodReference ReportRefValue { get; set; } - public MethodReference ReportSpanValue { get; set; } - public MethodReference ReportRefSpanValue { get; set; } - public MethodReference ReportReadOnlySpanValue { get; set; } - public MethodReference ReportRefReadOnlySpanValue { get; set; } - public MethodReference ReportException { get; set; } + default: return null; } } + + private struct ReportMethods { + public MethodReference ReportLineStart { get; set; } + public MethodReference ReportValue { get; set; } + public MethodReference ReportRefValue { get; set; } + public MethodReference ReportSpanValue { get; set; } + public MethodReference ReportRefSpanValue { get; set; } + public MethodReference ReportReadOnlySpanValue { get; set; } + public MethodReference ReportRefReadOnlySpanValue { get; set; } + public MethodReference ReportException { get; set; } + } } diff --git a/source/NetFramework/Server/Execution/Unbreakable/ArrayReturnRewriter.cs b/source/NetFramework/Server/Execution/Unbreakable/ArrayReturnRewriter.cs index 2ab0ea77c..84536a9ed 100644 --- a/source/NetFramework/Server/Execution/Unbreakable/ArrayReturnRewriter.cs +++ b/source/NetFramework/Server/Execution/Unbreakable/ArrayReturnRewriter.cs @@ -3,31 +3,31 @@ using Unbreakable.Policy.Internal; using SharpLab.Server.Execution.Internal; -namespace SharpLab.Server.Execution.Unbreakable { - internal class ArrayReturnRewriter : IMemberRewriterInternal { - public static ArrayReturnRewriter Default { get; } = new ArrayReturnRewriter(); +namespace SharpLab.Server.Execution.Unbreakable; - public string GetShortName() => nameof(ArrayReturnRewriter); +internal class ArrayReturnRewriter : IMemberRewriterInternal { + public static ArrayReturnRewriter Default { get; } = new ArrayReturnRewriter(); - public bool Rewrite(Instruction instruction, MemberRewriterContext context) { - var il = context.IL; + public string GetShortName() => nameof(ArrayReturnRewriter); - var method = ((MethodReference)instruction.Operand).Resolve(); - if (!method.ReturnType.IsArray) - return false; + public bool Rewrite(Instruction instruction, MemberRewriterContext context) { + var il = context.IL; - var dup = il.Create(OpCodes.Dup); - var ldlen = il.Create(OpCodes.Ldlen); - var ldloc = il.CreateLdlocBest(context.RuntimeGuardVariable); - var call = il.CreateCall(context.RuntimeGuardReferences.FlowThroughGuardCountIntPtrMethod); - var pop = il.Create(OpCodes.Pop); + var method = ((MethodReference)instruction.Operand).Resolve(); + if (!method.ReturnType.IsArray) + return false; - context.IL.InsertAfter(instruction, dup); - context.IL.InsertAfter(dup, ldlen); - context.IL.InsertAfter(ldlen, ldloc); - context.IL.InsertAfter(ldloc, call); - context.IL.InsertAfter(call, pop); - return true; - } + var dup = il.Create(OpCodes.Dup); + var ldlen = il.Create(OpCodes.Ldlen); + var ldloc = il.CreateLdlocBest(context.RuntimeGuardVariable); + var call = il.CreateCall(context.RuntimeGuardReferences.FlowThroughGuardCountIntPtrMethod); + var pop = il.Create(OpCodes.Pop); + + context.IL.InsertAfter(instruction, dup); + context.IL.InsertAfter(dup, ldlen); + context.IL.InsertAfter(ldlen, ldloc); + context.IL.InsertAfter(ldloc, call); + context.IL.InsertAfter(call, pop); + return true; } } diff --git a/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs b/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs new file mode 100644 index 000000000..2ca9d175a --- /dev/null +++ b/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs @@ -0,0 +1,22 @@ +using Microsoft.ApplicationInsights; +using SharpLab.Server.Monitoring; + +namespace SharpLab.Server.Integration.Azure; + +public class ApplicationInsightsMetricMonitor : IZeroDimensionMetricMonitor, IOneDimensionMetricMonitor { + private readonly Metric _metric; + + public ApplicationInsightsMetricMonitor(Metric metric) { + Argument.NotNull(nameof(metric), metric); + + _metric = metric; + } + + public void Track(double value) { + _metric.TrackValue(value); + } + + public void Track(string dimension, double value) { + _metric.TrackValue(value, dimension); + } +} \ No newline at end of file diff --git a/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMonitor.cs b/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMonitor.cs index 58f8a9182..7bc1fb8a3 100644 --- a/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMonitor.cs +++ b/source/NetFramework/Server/Integration/Azure/ApplicationInsightsMonitor.cs @@ -1,49 +1,98 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.ApplicationInsights; -using Microsoft.ApplicationInsights.Channel; using Microsoft.ApplicationInsights.DataContracts; +using Microsoft.ApplicationInsights.Metrics; using MirrorSharp.Advanced; +using MirrorSharp.Internal; +using Newtonsoft.Json; using SharpLab.Server.MirrorSharp; using SharpLab.Server.Monitoring; -namespace SharpLab.Server.Azure { - public class ApplicationInsightsMonitor : IMonitor { - private readonly TelemetryClient _client; - private readonly string _webAppName; +namespace SharpLab.Server.Integration.Azure; - public ApplicationInsightsMonitor(TelemetryClient client, string webAppName) { - _client = Argument.NotNull(nameof(client), client); - _webAppName = Argument.NotNullOrEmpty(nameof(webAppName), webAppName); - } +public class ApplicationInsightsMonitor : IMonitor { + private readonly TelemetryClient _client; + private readonly string _webAppName; + private readonly Func _createMetricMonitor; - public void Event(string name, IWorkSession? session, IDictionary? extras = null) { - var telemetry = new EventTelemetry(name); - AddDefaultDetails(telemetry, session, extras); - _client.TrackEvent(telemetry); - } + public ApplicationInsightsMonitor(TelemetryClient client, string webAppName, Func createMetricMonitor) { + _client = Argument.NotNull(nameof(client), client); + _webAppName = Argument.NotNullOrEmpty(nameof(webAppName), webAppName); + _createMetricMonitor = Argument.NotNull(nameof(createMetricMonitor), createMetricMonitor); + } - public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { - var telemetry = new ExceptionTelemetry(exception) { - Properties = { - { "Code", session?.GetText() } - } - }; - AddDefaultDetails(telemetry, session, extras); - _client.TrackException(telemetry); - } + public IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name) + => MetricSlowInternal(new (@namespace, name)); + + public IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension) + => MetricSlowInternal(new (@namespace, name, dimension)); - private void AddDefaultDetails(TTelemetry telemetry, IWorkSession? session, IDictionary? extras) - where TTelemetry: ITelemetry, ISupportProperties - { - telemetry.Context.Session.Id = session?.GetSessionId(); - telemetry.Properties.Add("Web App", _webAppName); - if (extras == null) - return; + private ApplicationInsightsMetricMonitor MetricSlowInternal(MetricIdentifier identifier) { + var metric = _client.GetMetric(identifier); + return _createMetricMonitor(metric); + } + + public void Event(string eventName, IWorkSession? session, IDictionary? extras = null) { + var telemetry = new EventTelemetry(eventName) { + Context = { Session = { Id = session?.GetSessionId() } }, + Properties = { + { "Web App", _webAppName } + } + }; + if (extras != null) { + foreach (var pair in extras) { + telemetry.Properties.Add(pair.Key, pair.Value); + } + } + _client.TrackEvent(telemetry); + } + public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { + var sessionInternals = session as WorkSession; + var telemetry = new ExceptionTelemetry(exception) { + Context = { Session = { Id = session?.GetSessionId() } }, + Properties = { + { "Web App", _webAppName }, + { "Code", session?.GetText() }, + { "Language", session?.LanguageName }, + { "Target", session?.GetTargetName() }, + { "Cursor", sessionInternals?.CursorPosition.ToString() }, + { "Completion", FormatCompletion(sessionInternals) } + } + }; + if (extras != null) { foreach (var pair in extras) { telemetry.Properties.Add(pair.Key, pair.Value); } } + _client.TrackException(telemetry); + } + + private string? FormatCompletion(WorkSession? session) { + try { + if (session == null) + return null; + + var current = session.CurrentCompletion; + if (current.List == null && !current.ChangeEchoPending && current.PendingChar == null) + return null; + + return JsonConvert.ToString(new { + List = current.List is { } list ? new { + Items = new { + Take10 = list.ItemsList.Take(10), + list.ItemsList.Count + }, + list.Span + } : null, + current.ChangeEchoPending, + current.PendingChar + }); + } + catch (Exception ex) { + return ""; + } } } diff --git a/source/NetFramework/Server/Integration/Azure/AzureModule.cs b/source/NetFramework/Server/Integration/Azure/AzureModule.cs index 39c5b4bc6..3fcc0cce8 100644 --- a/source/NetFramework/Server/Integration/Azure/AzureModule.cs +++ b/source/NetFramework/Server/Integration/Azure/AzureModule.cs @@ -1,27 +1,53 @@ -using System; +using System; using Autofac; +using Azure.Identity; +using Azure.Security.KeyVault.Secrets; using JetBrains.Annotations; using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.Extensibility; +using SharpLab.Server.Common; +using SharpLab.Server.Integration.Azure; using SharpLab.Server.Monitoring; -namespace SharpLab.Server.Azure { - [UsedImplicitly] - public class AzureModule : Module { - protected override void Load(ContainerBuilder builder) { - var instrumentationKey = Environment.GetEnvironmentVariable("SHARPLAB_TELEMETRY_KEY"); - if (instrumentationKey == null) - return; - - var configuration = new TelemetryConfiguration { InstrumentationKey = instrumentationKey }; - builder.RegisterInstance(new TelemetryClient(configuration)) - .AsSelf(); - - var webAppName = Environment.GetEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); - builder.RegisterType() - .As() - .WithParameter("webAppName", webAppName) - .SingleInstance(); - } +namespace SharpLab.Server.Azure; + +[UsedImplicitly] +public class AzureModule : Module { + protected override void Load(ContainerBuilder builder) { + var keyVaultUrl = Environment.GetEnvironmentVariable("SHARPLAB_KEY_VAULT_URL"); + if (keyVaultUrl == null) + return; + + RegisterKeyVault(builder, keyVaultUrl); + RegisterApplicationInsights(builder); + } + + private void RegisterKeyVault(ContainerBuilder builder, string keyVaultUrl) { + var secretClient = new SecretClient(new Uri(keyVaultUrl), new ManagedIdentityCredential()); + builder.RegisterInstance(secretClient) + .AsSelf(); + + builder.RegisterType() + .As() + .SingleInstance(); + } + + private void RegisterApplicationInsights(ContainerBuilder builder) { + builder.Register(c => { + var connectionString = c.Resolve().GetSecret("AppInsightsConnectionString"); + var configuration = new TelemetryConfiguration { ConnectionString = connectionString }; + return new TelemetryClient(configuration); + }).AsSelf() + .SingleInstance(); + + builder.RegisterType() + .AsSelf() + .InstancePerDependency(); + + var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); + builder.RegisterType() + .As() + .WithParameter("webAppName", webAppName) + .SingleInstance(); } } \ No newline at end of file diff --git a/source/NetFramework/Server/Integration/Azure/KeyVaultSecretsClient.cs b/source/NetFramework/Server/Integration/Azure/KeyVaultSecretsClient.cs new file mode 100644 index 000000000..eeaea9c81 --- /dev/null +++ b/source/NetFramework/Server/Integration/Azure/KeyVaultSecretsClient.cs @@ -0,0 +1,16 @@ +using Azure.Security.KeyVault.Secrets; +using SharpLab.Server.Common; + +namespace SharpLab.Server.Integration.Azure; + +public class KeyVaultSecretsClient : ISecretsClient { + private readonly SecretClient _secretClient; + + public KeyVaultSecretsClient(SecretClient secretClient) { + _secretClient = secretClient; + } + + public string GetSecret(string key) { + return _secretClient.GetSecret(key).Value.Value; + } +} diff --git a/source/NetFramework/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs b/source/NetFramework/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs index 36044b473..ce3e014d3 100644 --- a/source/NetFramework/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs +++ b/source/NetFramework/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs @@ -16,12 +16,24 @@ public void ValidateCompilation(CSharpCompilation compilation) { throw new RoslynCompilationGuardException("Reference exceeded type nesting limit: " + qualified); } - foreach (var generic in root.DescendantNodes().OfType()) { + foreach (var generic in root.DescendantNodes(static n => n is not TypeParameterListSyntax).OfType()) { if (generic.Parameters.Count > 4) throw new RoslynCompilationGuardException("Generic parameter list exceeded size limit: " + generic); } + foreach (var generic in root.DescendantNodes(static n => n is not TypeArgumentListSyntax).OfType()) { + if (GetTotalGenericArgumentCount(generic) > 4) + throw new RoslynCompilationGuardException("Generic argument list exceeded size limit: " + generic); + } + } + } + + private int GetTotalGenericArgumentCount(TypeArgumentListSyntax generic) { + var count = 0; + foreach (var subgeneric in generic.DescendantNodesAndSelf().OfType()) { + count += subgeneric.Arguments.Count; } + return count; } } } diff --git a/source/NetFramework/Server/MirrorSharp/MirrorSharpModule.cs b/source/NetFramework/Server/MirrorSharp/MirrorSharpModule.cs index 4392deeea..e59acfbdf 100644 --- a/source/NetFramework/Server/MirrorSharp/MirrorSharpModule.cs +++ b/source/NetFramework/Server/MirrorSharp/MirrorSharpModule.cs @@ -5,34 +5,39 @@ using MirrorSharp.Advanced; using MirrorSharp.Advanced.EarlyAccess; using SharpLab.Server.MirrorSharp.Guards; +using SharpLab.Server.Monitoring; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly] - public class MirrorSharpModule : Module { - protected override void Load(ContainerBuilder builder) { - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As>() - .SingleInstance(); - - builder.RegisterType() - .As>() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - } +namespace SharpLab.Server.MirrorSharp; + +[UsedImplicitly] +public class MirrorSharpModule : Module { + protected override void Load(ContainerBuilder builder) { + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As>() + .SingleInstance(); + + builder.RegisterType() + .As>() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); } } \ No newline at end of file diff --git a/source/NetFramework/Server/MirrorSharp/SetOptionsFromClient.cs b/source/NetFramework/Server/MirrorSharp/SetOptionsFromClient.cs index 353a5cb4b..89aea8d39 100644 --- a/source/NetFramework/Server/MirrorSharp/SetOptionsFromClient.cs +++ b/source/NetFramework/Server/MirrorSharp/SetOptionsFromClient.cs @@ -4,34 +4,34 @@ using MirrorSharp.Advanced; using SharpLab.Server.Common; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class SetOptionsFromClient : ISetOptionsFromClientExtension { - private const string Optimize = "x-optimize"; - private const string Target = "x-target"; - private const string ContainerExperimentSeed = "x-container-experiment-seed"; +namespace SharpLab.Server.MirrorSharp; - private readonly IDictionary _languages; +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class SetOptionsFromClient : ISetOptionsFromClientExtension { + private const string Optimize = "x-optimize"; + private const string Target = "x-target"; + private const string ContainerExperimentSeed = "x-container-experiment-seed"; - public SetOptionsFromClient(IReadOnlyList languages) { - _languages = languages.ToDictionary(l => l.LanguageName); - } + private readonly IDictionary _languages; + + public SetOptionsFromClient(IReadOnlyList languages) { + _languages = languages.ToDictionary(l => l.LanguageName); + } - public bool TrySetOption(IWorkSession session, string name, string value) { - switch (name) { - case Optimize: - _languages[session.LanguageName].SetOptimize(session, value); - return true; - case Target: - session.SetTargetName(value); - _languages[session.LanguageName].SetOptionsForTarget(session, value); - return true; - case ContainerExperimentSeed: - // TODO: remove once UI logic is removed (not supported in .NET Framework either way) - return true; - default: - return false; - } + public bool TrySetOption(IWorkSession session, string name, string value) { + switch (name) { + case Optimize: + _languages[session.LanguageName].SetOptimize(session, value); + return true; + case Target: + session.SetTargetName(value); + _languages[session.LanguageName].SetOptionsForTarget(session, value); + return true; + case ContainerExperimentSeed: + // TODO: remove once UI logic is removed (not supported in .NET Framework either way) + return true; + default: + return false; } } } \ No newline at end of file diff --git a/source/NetFramework/Server/MirrorSharp/SlowUpdate.cs b/source/NetFramework/Server/MirrorSharp/SlowUpdate.cs index d2aaf4723..9e122d7b6 100644 --- a/source/NetFramework/Server/MirrorSharp/SlowUpdate.cs +++ b/source/NetFramework/Server/MirrorSharp/SlowUpdate.cs @@ -17,139 +17,146 @@ using SharpLab.Server.Explanation; using LanguageNames = SharpLab.Server.Common.LanguageNames; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class SlowUpdate : ISlowUpdateExtension { - private readonly ICompiler _compiler; - private readonly IReadOnlyDictionary _decompilers; - private readonly IReadOnlyDictionary _astTargets; - private readonly IExecutor _executor; - private readonly IExplainer _explainer; - private readonly RecyclableMemoryStreamManager _memoryStreamManager; - - public SlowUpdate( - ICompiler compiler, - IReadOnlyCollection decompilers, - IReadOnlyCollection astTargets, - IExecutor executor, - IExplainer explainer, - RecyclableMemoryStreamManager memoryStreamManager - ) { - _compiler = compiler; - _decompilers = decompilers.ToDictionary(d => d.LanguageName); - _astTargets = astTargets - .SelectMany(t => t.SupportedLanguageNames.Select(n => (target: t, languageName: n))) - .ToDictionary(x => x.languageName, x => x.target); - _executor = executor; - _memoryStreamManager = memoryStreamManager; - _explainer = explainer; +namespace SharpLab.Server.MirrorSharp; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class SlowUpdate : ISlowUpdateExtension { + private readonly ICompiler _compiler; + private readonly IReadOnlyDictionary _decompilers; + private readonly IReadOnlyDictionary _astTargets; + private readonly IExecutor _executor; + private readonly IExplainer _explainer; + private readonly RecyclableMemoryStreamManager _memoryStreamManager; + private readonly IFeatureTracker _featureTracker; + + public SlowUpdate( + ICompiler compiler, + IReadOnlyCollection decompilers, + IReadOnlyCollection astTargets, + IExecutor executor, + IExplainer explainer, + RecyclableMemoryStreamManager memoryStreamManager, + IFeatureTracker featureTracker + ) { + _compiler = compiler; + _decompilers = decompilers.ToDictionary(d => d.LanguageName); + _astTargets = astTargets + .SelectMany(t => t.SupportedLanguageNames.Select(n => (target: t, languageName: n))) + .ToDictionary(x => x.languageName, x => x.target); + _executor = executor; + _memoryStreamManager = memoryStreamManager; + _explainer = explainer; + _featureTracker = featureTracker; + } + + public async Task ProcessAsync(IWorkSession session, IList diagnostics, CancellationToken cancellationToken) { + _featureTracker.TrackBranch(); + + var targetName = GetAndEnsureTargetName(session); + _featureTracker.TrackLanguage(session.LanguageName); + _featureTracker.TrackTarget(targetName); + + if (targetName == TargetNames.Ast || targetName == TargetNames.Explain) { + if (session.LanguageName == LanguageNames.IL) + throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported for IL."); + + var astTarget = _astTargets[session.LanguageName]; + var ast = await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false); + if (targetName == TargetNames.Explain) + return await _explainer.ExplainAsync(ast, session, cancellationToken).ConfigureAwait(false); + return ast; } - public async Task ProcessAsync(IWorkSession session, IList diagnostics, CancellationToken cancellationToken) { - var targetName = GetAndEnsureTargetName(session); + if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) + return null; - if (targetName == TargetNames.Ast || targetName == TargetNames.Explain) { - if (session.LanguageName == LanguageNames.IL) - throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported for IL."); + if (targetName == LanguageNames.VisualBasic) + return VisualBasicNotAvailable; - var astTarget = _astTargets[session.LanguageName]; - var ast = await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false); - if (targetName == TargetNames.Explain) - return await _explainer.ExplainAsync(ast, session, cancellationToken).ConfigureAwait(false); - return ast; - } + if (targetName != TargetNames.Run && targetName != TargetNames.Verify && !_decompilers.ContainsKey(targetName)) + throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch."); - if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) - return null; + MemoryStream? assemblyStream = null; + MemoryStream? symbolStream = null; + try { + assemblyStream = _memoryStreamManager.GetStream(); + if (targetName == TargetNames.Run || targetName == TargetNames.IL) + symbolStream = _memoryStreamManager.GetStream(); - if (targetName == LanguageNames.VisualBasic) - return VisualBasicNotAvailable; - - if (targetName != TargetNames.Run && targetName != TargetNames.Verify && !_decompilers.ContainsKey(targetName)) - throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch."); - - MemoryStream? assemblyStream = null; - MemoryStream? symbolStream = null; - try { - assemblyStream = _memoryStreamManager.GetStream(); - if (targetName == TargetNames.Run || targetName == TargetNames.IL) - symbolStream = _memoryStreamManager.GetStream(); - - var compiled = await _compiler.TryCompileToStreamAsync(assemblyStream, symbolStream, session, diagnostics, cancellationToken).ConfigureAwait(false); - if (!compiled.assembly) { - assemblyStream.Dispose(); - symbolStream?.Dispose(); - return null; - } - - if (targetName == TargetNames.Verify) { - assemblyStream.Dispose(); - symbolStream?.Dispose(); - return "✔️ Compilation completed."; - } - - assemblyStream.Seek(0, SeekOrigin.Begin); - symbolStream?.Seek(0, SeekOrigin.Begin); - var streams = new CompilationStreamPair(assemblyStream, compiled.symbols ? symbolStream : null); - if (targetName == TargetNames.Run) - return _executor.Execute(streams, session); - - // it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult() - return streams; - } - catch { - assemblyStream?.Dispose(); + var compiled = await _compiler.TryCompileToStreamAsync(assemblyStream, symbolStream, session, diagnostics, cancellationToken).ConfigureAwait(false); + if (!compiled.assembly) { + assemblyStream.Dispose(); symbolStream?.Dispose(); - throw; + return null; } - } - public void WriteResult(IFastJsonWriter writer, object? result, IWorkSession session) { - if (result == null) { - writer.WriteValue((string?)null); - return; + if (targetName == TargetNames.Verify) { + assemblyStream.Dispose(); + symbolStream?.Dispose(); + return "✔️ Compilation completed."; } - if (result is string s) { - writer.WriteValue(s); - return; - } + assemblyStream.Seek(0, SeekOrigin.Begin); + symbolStream?.Seek(0, SeekOrigin.Begin); + var streams = new CompilationStreamPair(assemblyStream, compiled.symbols ? symbolStream : null); + if (targetName == TargetNames.Run) + return _executor.Execute(streams, session); - var targetName = GetAndEnsureTargetName(session); - if (targetName == TargetNames.Ast) { - var astTarget = _astTargets[session.LanguageName]; - astTarget.SerializeAst(result, writer, session); - return; - } + // it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult() + return streams; + } + catch { + assemblyStream?.Dispose(); + symbolStream?.Dispose(); + throw; + } + } - if (targetName == TargetNames.Explain) { - _explainer.Serialize((ExplanationResult)result, writer); - return; - } + public void WriteResult(IFastJsonWriter writer, object? result, IWorkSession session) { + if (result == null) { + writer.WriteValue((string?)null); + return; + } - if (targetName == TargetNames.Run) { - _executor.Serialize((ExecutionResult)result, writer); - return; - } + if (result is string s) { + writer.WriteValue(s); + return; + } - var decompiler = _decompilers[targetName]; - using (var streams = (CompilationStreamPair)result) - using (var stringWriter = writer.OpenString()) { - decompiler.Decompile(streams, stringWriter); - } + var targetName = GetAndEnsureTargetName(session); + if (targetName == TargetNames.Ast) { + var astTarget = _astTargets[session.LanguageName]; + astTarget.SerializeAst(result, writer, session); + return; } - private const string VisualBasicNotAvailable = - "' Unfortunately, Visual Basic decompilation is no longer supported.\r\n" + - "' \r\n" + - "' All decompilation in SharpLab is provided by ILSpy, and latest ILSpy does not suport VB.\r\n" + - "' If you are interested in VB, please discuss or contribute at https://github.com/icsharpcode/ILSpy."; - - private string GetAndEnsureTargetName(IWorkSession session) { - var targetName = session.GetTargetName(); - if (targetName == null) - throw new InvalidOperationException("Target is not set on the session (timing issue?). Please try reloading."); - return targetName; + if (targetName == TargetNames.Explain) { + _explainer.Serialize((ExplanationResult)result, writer); + return; } + + if (targetName == TargetNames.Run) { + _executor.Serialize((ExecutionResult)result, writer); + return; + } + + var decompiler = _decompilers[targetName]; + using (var streams = (CompilationStreamPair)result) + using (var stringWriter = writer.OpenString()) { + decompiler.Decompile(streams, stringWriter); + } + } + + private const string VisualBasicNotAvailable = + "' Unfortunately, Visual Basic decompilation is no longer supported.\r\n" + + "' \r\n" + + "' All decompilation in SharpLab is provided by ILSpy, and latest ILSpy does not suport VB.\r\n" + + "' If you are interested in VB, please discuss or contribute at https://github.com/icsharpcode/ILSpy."; + + private string GetAndEnsureTargetName(IWorkSession session) { + var targetName = session.GetTargetName(); + if (targetName == null) + throw new InvalidOperationException("Target is not set on the session (timing issue?). Please try reloading."); + return targetName; } } \ No newline at end of file diff --git a/source/NetFramework/Server/Monitoring/DefaultTraceMetricMonitor.cs b/source/NetFramework/Server/Monitoring/DefaultTraceMetricMonitor.cs new file mode 100644 index 000000000..fb3631d49 --- /dev/null +++ b/source/NetFramework/Server/Monitoring/DefaultTraceMetricMonitor.cs @@ -0,0 +1,24 @@ +using System.Diagnostics; + +namespace SharpLab.Server.Monitoring; + +public class DefaultTraceMetricMonitor : IZeroDimensionMetricMonitor, IOneDimensionMetricMonitor { + private readonly string _namespace; + private readonly string _name; + + public DefaultTraceMetricMonitor(string @namespace, string name) { + Argument.NotNullOrEmpty(nameof(@namespace), @namespace); + Argument.NotNullOrEmpty(nameof(name), name); + + _namespace = @namespace; + _name = name; + } + + public void Track(double value) { + Trace.TraceInformation("Metric {0} {1}: {2}.", _namespace, _name, value); + } + + public void Track(string dimension, double value) { + Trace.TraceInformation("Metric {0} {1}: {2} {3}.", _namespace, _name, dimension, value); + } +} diff --git a/source/NetFramework/Server/Monitoring/DefaultTraceMonitor.cs b/source/NetFramework/Server/Monitoring/DefaultTraceMonitor.cs index 27121a69c..8276ec652 100644 --- a/source/NetFramework/Server/Monitoring/DefaultTraceMonitor.cs +++ b/source/NetFramework/Server/Monitoring/DefaultTraceMonitor.cs @@ -4,14 +4,30 @@ using MirrorSharp.Advanced; using SharpLab.Server.MirrorSharp; -namespace SharpLab.Server.Monitoring { - public class DefaultTraceMonitor : IMonitor { - public void Event(string name, IWorkSession? session, IDictionary? extras = null) { - Trace.TraceInformation("[{0}] Event '{0}'.", session?.GetSessionId(), name); - } +namespace SharpLab.Server.Monitoring; - public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { - Trace.TraceError("[{0}] Exception: {0}.", session?.GetSessionId(), exception); - } +public class DefaultTraceMonitor : IMonitor { + private readonly Func<(string @namespace, string name), DefaultTraceMetricMonitor> _createMetricMonitor; + + public DefaultTraceMonitor( + Func<(string @namespace, string name), DefaultTraceMetricMonitor> createMetricMonitor + ) { + _createMetricMonitor = createMetricMonitor; + } + + public IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name) { + return _createMetricMonitor((@namespace, name)); + } + + public IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension) { + return _createMetricMonitor((@namespace, name)); + } + + public void Event(string eventName, IWorkSession? session, IDictionary? extras = null) { + Trace.TraceInformation("[{0}] Event: {1}.", session?.GetSessionId(), eventName); + } + + public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { + Trace.TraceError("[{0}] Exception: {1}.", session?.GetSessionId(), exception); } } diff --git a/source/NetFramework/Server/Monitoring/IMonitor.cs b/source/NetFramework/Server/Monitoring/IMonitor.cs index 338bde9bf..77262ec5d 100644 --- a/source/NetFramework/Server/Monitoring/IMonitor.cs +++ b/source/NetFramework/Server/Monitoring/IMonitor.cs @@ -2,9 +2,10 @@ using System.Collections.Generic; using MirrorSharp.Advanced; -namespace SharpLab.Server.Monitoring { - public interface IMonitor { - void Event(string name, IWorkSession? session, IDictionary? extras = null); - void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null); - } +namespace SharpLab.Server.Monitoring; +public interface IMonitor { + IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name); + IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension); + void Event(string eventName, IWorkSession? session, IDictionary? extras = null); + void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null); } diff --git a/source/NetFramework/Server/Monitoring/IOneDimensionMetricMonitor.cs b/source/NetFramework/Server/Monitoring/IOneDimensionMetricMonitor.cs new file mode 100644 index 000000000..1d72a3333 --- /dev/null +++ b/source/NetFramework/Server/Monitoring/IOneDimensionMetricMonitor.cs @@ -0,0 +1,5 @@ +namespace SharpLab.Server.Monitoring; + +public interface IOneDimensionMetricMonitor { + void Track(string dimension, double value); +} diff --git a/source/NetFramework/Server/Monitoring/IZeroDimensionMetricMonitor.cs b/source/NetFramework/Server/Monitoring/IZeroDimensionMetricMonitor.cs new file mode 100644 index 000000000..2aac8df2f --- /dev/null +++ b/source/NetFramework/Server/Monitoring/IZeroDimensionMetricMonitor.cs @@ -0,0 +1,5 @@ +namespace SharpLab.Server.Monitoring; + +public interface IZeroDimensionMetricMonitor { + void Track(double value); +} diff --git a/source/NetFramework/Server/Monitoring/MonitorExceptionLogger.cs b/source/NetFramework/Server/Monitoring/MonitorExceptionLogger.cs index 8a3f36964..ca6f196d1 100644 --- a/source/NetFramework/Server/Monitoring/MonitorExceptionLogger.cs +++ b/source/NetFramework/Server/Monitoring/MonitorExceptionLogger.cs @@ -1,19 +1,19 @@ -using System; +using System; using System.Net.WebSockets; using MirrorSharp.Advanced; -namespace SharpLab.Server.Monitoring { - public class MonitorExceptionLogger : IExceptionLogger { - private readonly IMonitor _monitor; +namespace SharpLab.Server.Monitoring; - public MonitorExceptionLogger(IMonitor monitor) { - _monitor = monitor; - } +public class MonitorExceptionLogger : IExceptionLogger { + private readonly IMonitor _monitor; - public void LogException(Exception exception, IWorkSession session) { - if (exception is WebSocketException) - return; - _monitor.Exception(exception, session); - } + public MonitorExceptionLogger(IMonitor monitor) { + _monitor = monitor; + } + + public void LogException(Exception exception, IWorkSession session) { + if (exception is WebSocketException) + return; + _monitor.Exception(exception, session); } } diff --git a/source/NetFramework/Server/Monitoring/MonitoringModule.cs b/source/NetFramework/Server/Monitoring/MonitoringModule.cs index 6a84a8c09..1fdd57299 100644 --- a/source/NetFramework/Server/Monitoring/MonitoringModule.cs +++ b/source/NetFramework/Server/Monitoring/MonitoringModule.cs @@ -1,19 +1,28 @@ using Autofac; using JetBrains.Annotations; -using MirrorSharp.Advanced; +using System; -namespace SharpLab.Server.Monitoring { - [UsedImplicitly] - public class MonitoringModule : Module { - protected override void Load(ContainerBuilder builder) { - builder.RegisterType() - .As() - .SingleInstance() - .PreserveExistingDefaults(); +namespace SharpLab.Server.Monitoring; +[UsedImplicitly] +public class MonitoringModule : Module { + protected override void Load(ContainerBuilder builder) { + builder.RegisterType() + .AsSelf() + .InstancePerDependency(); - builder.RegisterType() - .As() - .SingleInstance(); - } + builder.RegisterType() + .As() + .WithParameter( + (p, _) => p.ParameterType == typeof(Func<(string, string), DefaultTraceMetricMonitor>), + (_, c) => { + var context = c.Resolve(); + return ((string @namespace, string name) args) => context.Resolve( + new NamedParameter("namespace", args.@namespace), + new NamedParameter("name", args.name) + ); + } + ) + .SingleInstance() + .PreserveExistingDefaults(); } } \ No newline at end of file diff --git a/source/NetFramework/Server/Platform/Net48AssemblyDocumentationResolver.cs b/source/NetFramework/Server/Platform/Net48AssemblyDocumentationResolver.cs index 6b981cfa1..8a691bb17 100644 --- a/source/NetFramework/Server/Platform/Net48AssemblyDocumentationResolver.cs +++ b/source/NetFramework/Server/Platform/Net48AssemblyDocumentationResolver.cs @@ -10,7 +10,7 @@ namespace SharpLab.Server.Owin.Platform { public class Net48AssemblyDocumentationResolver : IAssemblyDocumentationResolver { private static readonly string ReferenceAssemblyRootPath = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86) - + @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7"; + + @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8"; public DocumentationProvider? GetDocumentation([NotNull] Assembly assembly) { foreach (var xmlPath in GetCandidatePaths(assembly)) { diff --git a/source/NetFramework/Server/Server.csproj b/source/NetFramework/Server/Server.csproj index 2e70601d4..3a9074b7b 100644 --- a/source/NetFramework/Server/Server.csproj +++ b/source/NetFramework/Server/Server.csproj @@ -20,36 +20,39 @@ + + - + - - - - - + + + + + - - - + + + + - - + + - - - - - + + + + + diff --git a/source/NetFramework/Server/StartupHelper.cs b/source/NetFramework/Server/StartupHelper.cs index 02b1e5be5..0867478ef 100644 --- a/source/NetFramework/Server/StartupHelper.cs +++ b/source/NetFramework/Server/StartupHelper.cs @@ -8,43 +8,43 @@ using MirrorSharp.Owin; using SharpLab.Server.Common; -namespace SharpLab.Server { - public static class StartupHelper { - // Chrome would limit to 10 mins I believe - public static readonly TimeSpan CorsPreflightMaxAge = TimeSpan.FromHours(1); - - public static void ConfigureContainer(ContainerBuilder builder) { - var assembly = Assembly.GetExecutingAssembly(); +namespace SharpLab.Server; - builder - .RegisterAssemblyModulesInDirectoryOf(assembly) - .WhereFileMatches("SharpLab.*"); - } +public static class StartupHelper { + // Chrome would limit to 10 mins I believe + public static readonly TimeSpan CorsPreflightMaxAge = TimeSpan.FromHours(1); + + public static void ConfigureContainer(ContainerBuilder builder) { + var assembly = Assembly.GetExecutingAssembly(); + + builder + .RegisterAssemblyModulesInDirectoryOf(assembly) + .WhereFileMatches("SharpLab.*"); + } - public static MirrorSharpOptions CreateMirrorSharpOptions(ILifetimeScope container) { - var options = new MirrorSharpOptions { - IncludeExceptionDetails = true, - StatusTestCommands = { - ('O', "x-optimize=debug,x-target=C#,x-no-cache=true,language=C#"), - ('R', "0:0:0::using System; public class C { public void M() { } }"), - ('U', "") - } - }; - var languages = container.Resolve(); - foreach (var language in languages) { - language.SlowSetup(options); + public static MirrorSharpOptions CreateMirrorSharpOptions(ILifetimeScope container) { + var options = new MirrorSharpOptions { + IncludeExceptionDetails = true, + StatusTestCommands = { + ('O', "x-optimize=debug,x-target=C#,x-no-cache=true,language=C#"), + ('R', "0:0:0::using System; public class C { public void M() { } }"), + ('U', "") } - return options; + }; + var languages = container.Resolve(); + foreach (var language in languages) { + language.SlowSetup(options); } + return options; + } - public static MirrorSharpServices CreateMirrorSharpServices(ILifetimeScope container) { - return new MirrorSharpServices { - SetOptionsFromClient = container.Resolve(), - SlowUpdate = container.Resolve(), - RoslynSourceTextGuard = container.Resolve(), - RoslynCompilationGuard = container.Resolve(), - ExceptionLogger = container.Resolve() - }; - } + public static MirrorSharpServices CreateMirrorSharpServices(ILifetimeScope container) { + return new MirrorSharpServices { + SetOptionsFromClient = container.Resolve(), + SlowUpdate = container.Resolve(), + RoslynSourceTextGuard = container.Resolve(), + RoslynCompilationGuard = container.Resolve(), + ExceptionLogger = container.Resolve() + }; } } diff --git a/source/NetFramework/Server/Web.config b/source/NetFramework/Server/Web.config index 6b4099a95..d18bd3cd3 100644 --- a/source/NetFramework/Server/Web.config +++ b/source/NetFramework/Server/Web.config @@ -45,37 +45,37 @@ - + - + - + - + - + - + @@ -87,19 +87,25 @@ - + - + - + + + + + + + @@ -111,7 +117,7 @@ - + @@ -132,5 +138,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/GeneralTests.cs b/source/NetFramework/Tests/Decompilation/GeneralTests.cs index 22bd4078b..33d133591 100644 --- a/source/NetFramework/Tests/Decompilation/GeneralTests.cs +++ b/source/NetFramework/Tests/Decompilation/GeneralTests.cs @@ -6,162 +6,162 @@ using Xunit; using Xunit.Abstractions; -namespace SharpLab.Tests.Decompilation { - public class GeneralTests { - private readonly ITestOutputHelper _output; - - public GeneralTests(ITestOutputHelper output) { - _output = output; - // TestAssemblyLog.Enable(output); - } - - [Theory] - [InlineData("class C { void M((int, string) t) {} }")] // Tuples, https://github.com/ashmind/SharpLab/issues/139 - public async Task SlowUpdate_DecompilesSimpleCodeWithoutErrors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - Assert.True(string.IsNullOrEmpty(errors), errors); - Assert.NotNull(result.ExtensionResult); - Assert.NotEmpty(result.ExtensionResult); - } - - [Theory] - [InlineData("Constructor.BaseCall.cs2cs")] - [InlineData("NullPropagation.ToTernary.cs2cs")] - [InlineData("Simple.cs2il")] - [InlineData("Simple.vb2cs")] - [InlineData("Module.vb2cs")] - [InlineData("Lambda.CallInArray.cs2cs")] // https://github.com/ashmind/SharpLab/issues/9 - [InlineData("Cast.ExplicitOperatorOnNull.cs2cs")] // https://github.com/ashmind/SharpLab/issues/20 - [InlineData("Goto.TryWhile.cs2cs")] // https://github.com/ashmind/SharpLab/issues/123 - [InlineData("Nullable.OperatorLifting.cs2cs")] // https://github.com/ashmind/SharpLab/issues/159 - [InlineData("Finalizer.Exception.cs2il")] // https://github.com/ashmind/SharpLab/issues/205 - [InlineData("Parameters.Optional.Decimal.cs2cs")] // https://github.com/ashmind/SharpLab/issues/316 - [InlineData("Unsafe.FixedBuffer.cs2cs")] // https://github.com/ashmind/SharpLab/issues/398 - public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) { - var code = TestCode.FromFile(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(code); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); - } - - [Theory] - [InlineData("Condition.SimpleSwitch.cs2cs")] // https://github.com/ashmind/SharpLab/issues/25 - //[InlineData("Variable.FromArgumentToCall.cs2cs")] // https://github.com/ashmind/SharpLab/issues/128 - [InlineData("Preprocessor.IfDebug.cs2cs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("Preprocessor.IfDebug.vb2cs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("FSharp/Preprocessor.IfDebug.fs2cs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("Using.Simple.cs2cs")] // https://github.com/ashmind/SharpLab/issues/185 - [InlineData("StringInterpolation.Simple.cs")] - public async Task SlowUpdate_ReturnsExpectedDecompiledCode_InDebug(string codeFilePath) { - var data = TestCode.FromFile(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(data, Optimize.Debug); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - data.AssertIsExpected(decompiledText, _output); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "/// \r\npublic class C {}", "CS1574")] // https://github.com/ashmind/SharpLab/issues/219 - [InlineData(LanguageNames.VisualBasic, "''' \r\nPublic Class C\r\nEnd Class", "BC42309")] - public async Task SlowUpdate_ReturnsExpectedWarnings_ForXmlDocumentation(string sourceLanguageName, string code, string expectedWarningId) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); - - var result = await driver.SendSlowUpdateAsync(); - Assert.Equal( - new[] { new { Severity = "warning", Id = expectedWarningId } }, - result.Diagnostics.Select(d => new { d.Severity, d.Id }).ToArray() - ); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "public class C {}")] - [InlineData(LanguageNames.VisualBasic, "Public Class C\r\nEnd Class")] - public async Task SlowUpdate_DoesNotReturnWarnings_ForCodeWithoutXmlDocumentation(string sourceLanguageName, string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); - - var result = await driver.SendSlowUpdateAsync(); - Assert.Empty(result.Diagnostics); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "class X { class Y: X {Y.Y.Y.Y.Y.Y.Y.Y.Y y; } }")] // https://codegolf.stackexchange.com/a/69200 - [InlineData(LanguageNames.VisualBasic, @" +namespace SharpLab.Tests.Decompilation; + +public class GeneralTests { + private readonly ITestOutputHelper _output; + + public GeneralTests(ITestOutputHelper output) { + _output = output; + // TestAssemblyLog.Enable(output); + } + + [Theory] + [InlineData("class C { void M((int, string) t) {} }")] // Tuples, https://github.com/ashmind/SharpLab/issues/139 + public async Task SlowUpdate_DecompilesSimpleCodeWithoutErrors(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + Assert.True(string.IsNullOrEmpty(errors), errors); + Assert.NotNull(result.ExtensionResult); + Assert.NotEmpty(result.ExtensionResult); + } + + [Theory] + [InlineData("Constructor.BaseCall.cs")] + [InlineData("NullPropagation.ToTernary.cs")] + [InlineData("Simple.cs")] + [InlineData("Simple.vb2cs")] + [InlineData("Module.vb2cs")] + [InlineData("Lambda.CallInArray.cs")] // https://github.com/ashmind/SharpLab/issues/9 + [InlineData("Cast.ExplicitOperatorOnNull.cs")] // https://github.com/ashmind/SharpLab/issues/20 + [InlineData("Goto.TryWhile.cs")] // https://github.com/ashmind/SharpLab/issues/123 + [InlineData("Nullable.OperatorLifting.cs")] // https://github.com/ashmind/SharpLab/issues/159 + [InlineData("Finalizer.Exception.cs")] // https://github.com/ashmind/SharpLab/issues/205 + [InlineData("Parameters.Optional.Decimal.cs")] // https://github.com/ashmind/SharpLab/issues/316 + [InlineData("Unsafe.FixedBuffer.cs")] // https://github.com/ashmind/SharpLab/issues/398 + public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) { + var code = TestCode.FromFile(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(code); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await code.AssertIsExpectedAsync(decompiledText, _output); + } + + [Theory] + [InlineData("Condition.SimpleSwitch.cs")] // https://github.com/ashmind/SharpLab/issues/25 + //[InlineData("Variable.FromArgumentToCall.cs2cs")] // https://github.com/ashmind/SharpLab/issues/128 + [InlineData("Preprocessor.IfDebug.cs")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("Preprocessor.IfDebug.vb2cs")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("FSharp/Preprocessor.IfDebug.fs")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("Using.Simple.cs")] // https://github.com/ashmind/SharpLab/issues/185 + [InlineData("StringInterpolation.Simple.cs")] + public async Task SlowUpdate_ReturnsExpectedDecompiledCode_InDebug(string codeFilePath) { + var data = TestCode.FromFile(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(data, Optimize.Debug); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await data.AssertIsExpectedAsync(decompiledText, _output); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "/// \r\npublic class C {}", "CS1574")] // https://github.com/ashmind/SharpLab/issues/219 + [InlineData(LanguageNames.VisualBasic, "''' \r\nPublic Class C\r\nEnd Class", "BC42309")] + public async Task SlowUpdate_ReturnsExpectedWarnings_ForXmlDocumentation(string sourceLanguageName, string code, string expectedWarningId) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); + + var result = await driver.SendSlowUpdateAsync(); + Assert.Contains( + new { Severity = "warning", Id = expectedWarningId }, + result.Diagnostics.Select(d => new { d.Severity, d.Id }).ToArray() + ); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "public class C {}")] + [InlineData(LanguageNames.VisualBasic, "Public Class C\r\nEnd Class")] + public async Task SlowUpdate_DoesNotReturnWarnings_ForCodeWithoutXmlDocumentation(string sourceLanguageName, string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); + + var result = await driver.SendSlowUpdateAsync(); + Assert.DoesNotContain(result.Diagnostics, d => d.Severity is "warning" or "error"); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "class X { class Y: X {Y.Y.Y.Y.Y.Y.Y.Y.Y y; } }")] // https://codegolf.stackexchange.com/a/69200 + [InlineData(LanguageNames.VisualBasic, @" Class X (Of A, B, C, D, E) Class Y Inherits X (Of Y, Y, Y, Y, Y) Private y As Y.Y.Y.Y.Y.Y.Y.Y.Y End Class End Class ")] - public async Task SlowUpdate_ReturnsRoslynGuardException_ForCompilerBombs(string languageName, string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(languageName, TargetNames.IL); - - await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); - } - - [Theory] - [InlineData("x[][][][][]")] - [InlineData("x [,,,] [,] [,,,] [,,,] [,]")] - [InlineData("x [] [] [] [] []")] - [InlineData("x[1][2][3][4][5]")] - [InlineData("x[[[[[][][][][]]]]]")] - [InlineData("x[[[[[[]]]]]]")] - [InlineData("x()()()()()")] - [InlineData("x (,,,) (,) (,,,) (,,,) (,)")] - [InlineData("x () () () () ()")] - [InlineData("x(1)(2)(3)(4)(5)")] - [InlineData("x((((()()()()()))))")] - [InlineData("x(((((())))))")] - public async Task SetOptions_ReturnsRoslynGuardException_ForTextExceedingTokenLimits(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - - await Assert.ThrowsAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); - } - - [Theory] - [InlineData("Append(Append(Append(Append(hash, (byte)value), value>>8), value>>16), value>>24)")] - public async Task SetOptions_ProcessesTokenEdgeCases_WithoutTokenValidationErrors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - - var exception = await Record.ExceptionAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); - - Assert.Null(exception); - } - - [Fact] // https://github.com/ashmind/SharpLab/issues/817 - public async Task SlowUpdate_DoesNotReportAnyErrors_WhenSwitchingFromTopLevelStatementsToNonTopLevel() { - // Arrange - var code = "class C { void M() {} }"; - var driver = TestEnvironment.NewDriver().SetTextWithCursor(code + "|"); - await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); - // switches to top-level statement mode - await driver.SendTypeCharAsync('+'); - await driver.SendSlowUpdateAsync(); - // switches back (removes + at the end) - await driver.SendBackspaceAsync(); - - // Act - var result = await driver.SendSlowUpdateAsync(); - - // Assert - var errors = result.JoinErrors(); - Assert.True(string.IsNullOrEmpty(errors), errors); - } + public async Task SlowUpdate_ReturnsRoslynGuardException_ForCompilerBombs(string languageName, string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(languageName, TargetNames.IL); + + await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); + } + + [Theory] + [InlineData("x[][][][][]")] + [InlineData("x [,,,] [,] [,,,] [,,,] [,]")] + [InlineData("x [] [] [] [] []")] + [InlineData("x[1][2][3][4][5]")] + [InlineData("x[[[[[][][][][]]]]]")] + [InlineData("x[[[[[[]]]]]]")] + [InlineData("x()()()()()")] + [InlineData("x (,,,) (,) (,,,) (,,,) (,)")] + [InlineData("x () () () () ()")] + [InlineData("x(1)(2)(3)(4)(5)")] + [InlineData("x((((()()()()()))))")] + [InlineData("x(((((())))))")] + public async Task SetOptions_ReturnsRoslynGuardException_ForTextExceedingTokenLimits(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + + await Assert.ThrowsAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); + } + + [Theory] + [InlineData("Append(Append(Append(Append(hash, (byte)value), value>>8), value>>16), value>>24)")] + public async Task SetOptions_ProcessesTokenEdgeCases_WithoutTokenValidationErrors(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + + var exception = await Record.ExceptionAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); + + Assert.Null(exception); + } + + [Fact] // https://github.com/ashmind/SharpLab/issues/817 + public async Task SlowUpdate_DoesNotReportAnyErrors_WhenSwitchingFromTopLevelStatementsToNonTopLevel() { + // Arrange + var code = "class C { void M() {} }"; + var driver = TestEnvironment.NewDriver().SetTextWithCursor(code + "|"); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); + // switches to top-level statement mode + await driver.SendTypeCharAsync('+'); + await driver.SendSlowUpdateAsync(); + // switches back (removes + at the end) + await driver.SendBackspaceAsync(); + + // Act + var result = await driver.SendSlowUpdateAsync(); + + // Assert + var errors = result.JoinErrors(); + Assert.True(string.IsNullOrEmpty(errors), errors); } } diff --git a/source/NetFramework/Tests/Decompilation/LanguageFSharpTests.cs b/source/NetFramework/Tests/Decompilation/LanguageFSharpTests.cs index 1313f6abe..9851b8d3a 100644 --- a/source/NetFramework/Tests/Decompilation/LanguageFSharpTests.cs +++ b/source/NetFramework/Tests/Decompilation/LanguageFSharpTests.cs @@ -3,29 +3,29 @@ using Xunit.Abstractions; using SharpLab.Tests.Internal; -namespace SharpLab.Tests.Decompilation { - public class LanguageFSharpTests { - private readonly ITestOutputHelper _output; +namespace SharpLab.Tests.Decompilation; - public LanguageFSharpTests(ITestOutputHelper output) { - _output = output; - // TestAssemblyLog.Enable(output); - } +public class LanguageFSharpTests { + private readonly ITestOutputHelper _output; - [Theory] - [InlineData("FSharp/EmptyType.fs")] - [InlineData("FSharp/SimpleMethod.fs2cs")] // https://github.com/ashmind/SharpLab/issues/119 - [InlineData("FSharp/NotNull.fs2cs")] - public async Task SlowUpdate_ReturnsExpectedDecompiledCode_ForFSharp(string codeFilePath) { - var code = TestCode.FromFile(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(code); + public LanguageFSharpTests(ITestOutputHelper output) { + _output = output; + // TestAssemblyLog.Enable(output); + } + + [Theory] + [InlineData("FSharp/EmptyType.fs")] + [InlineData("FSharp/SimpleMethod.fs")] // https://github.com/ashmind/SharpLab/issues/119 + [InlineData("FSharp/NotNull.fs")] + public async Task SlowUpdate_ReturnsExpectedDecompiledCode_ForFSharp(string codeFilePath) { + var code = TestCode.FromFile(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(code); - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); - } + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await code.AssertIsExpectedAsync(decompiledText, _output); } } diff --git a/source/NetFramework/Tests/Decompilation/LanguageILTests.cs b/source/NetFramework/Tests/Decompilation/LanguageILTests.cs index 265b5ce05..9c267dd7e 100644 --- a/source/NetFramework/Tests/Decompilation/LanguageILTests.cs +++ b/source/NetFramework/Tests/Decompilation/LanguageILTests.cs @@ -28,7 +28,7 @@ public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) var decompiledText = result.ExtensionResult?.Trim(); Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); + await code.AssertIsExpectedAsync(decompiledText, _output); } [Fact] diff --git a/source/NetFramework/Tests/Decompilation/TargetAstTests.cs b/source/NetFramework/Tests/Decompilation/TargetAstTests.cs index 208e71bc4..33f3f1e67 100644 --- a/source/NetFramework/Tests/Decompilation/TargetAstTests.cs +++ b/source/NetFramework/Tests/Decompilation/TargetAstTests.cs @@ -4,30 +4,30 @@ using Xunit.Abstractions; using SharpLab.Tests.Internal; -namespace SharpLab.Tests.Decompilation { - public class TargetAstTests { - private readonly ITestOutputHelper _output; +namespace SharpLab.Tests.Decompilation; - public TargetAstTests(ITestOutputHelper output) { - _output = output; - // TestAssemblyLog.Enable(output); - } +public class TargetAstTests { + private readonly ITestOutputHelper _output; - [Theory] - [InlineData("Ast/EmptyClass.cs2ast")] - [InlineData("Ast/StructuredTrivia.cs2ast")] - [InlineData("Ast/LiteralTokens.cs2ast")] - [InlineData("Ast/EmptyType.fs")] - [InlineData("Ast/LiteralTokens.fs")] - public async Task SlowUpdate_ReturnsExpectedResult(string codeFilePath) { - var code = TestCode.FromFile(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(code); + public TargetAstTests(ITestOutputHelper output) { + _output = output; + // TestAssemblyLog.Enable(output); + } + + [Theory] + [InlineData("Ast/EmptyClass.cs2ast")] + [InlineData("Ast/StructuredTrivia.cs2ast")] + [InlineData("Ast/LiteralTokens.cs2ast")] + [InlineData("Ast/EmptyType.fs")] + [InlineData("Ast/LiteralTokens.fs")] + public async Task SlowUpdate_ReturnsExpectedResult(string codeFilePath) { + var code = TestCode.FromFile(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(code); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - var json = result.ExtensionResult?.ToString(); + var json = result.ExtensionResult?.ToString(); - code.AssertIsExpected(json, _output); - } + await code.AssertIsExpectedAsync(json, _output); } } diff --git a/source/NetFramework/Tests/Decompilation/TargetJitAsmTests.cs b/source/NetFramework/Tests/Decompilation/TargetJitAsmTests.cs index 8876ecaad..dc62e2845 100644 --- a/source/NetFramework/Tests/Decompilation/TargetJitAsmTests.cs +++ b/source/NetFramework/Tests/Decompilation/TargetJitAsmTests.cs @@ -15,9 +15,9 @@ public TargetJitAsmTests(ITestOutputHelper output) { } [Theory] - [InlineData("JitAsm/Simple.cs2asm")] - [InlineData("JitAsm/MultipleReturns.cs2asm")] - [InlineData("JitAsm/ArrayElement.cs2asm")] + [InlineData("JitAsm/Simple.cs")] + [InlineData("JitAsm/MultipleReturns.cs")] + [InlineData("JitAsm/ArrayElement.cs")] // TODO: Understand why these tests are flaky and keep switching between // resolving and non-resolving symbols. Since it's .NET Framework, low priority. // @@ -28,11 +28,11 @@ public TargetJitAsmTests(ITestOutputHelper output) { // Resolving // [InlineData("JitAsm/AsyncRegression.cs2asm")] // [InlineData("JitAsm/ConsoleWrite.cs2asm")] - [InlineData("JitAsm/JumpBack.cs2asm")] // https://github.com/ashmind/SharpLab/issues/229 - [InlineData("JitAsm/Delegate.cs2asm")] - [InlineData("JitAsm/Nested.Simple.cs2asm")] - [InlineData("JitAsm/Generic.Open.Multiple.cs2asm")] - [InlineData("JitAsm/Generic.MethodWithAttribute.cs2asm")] + [InlineData("JitAsm/JumpBack.cs")] // https://github.com/ashmind/SharpLab/issues/229 + [InlineData("JitAsm/Delegate.cs")] + [InlineData("JitAsm/Nested.Simple.cs")] + [InlineData("JitAsm/Generic.Open.Multiple.cs")] + [InlineData("JitAsm/Generic.MethodWithAttribute.cs")] [InlineData("JitAsm/Generic.ClassWithAttribute.cs")] // TODO: Diagnose later // [InlineData("JitAsm/Generic.MethodWithAttribute.fs2asm")] @@ -49,18 +49,60 @@ public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) var decompiledText = result.ExtensionResult?.Trim(); Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); + await code.AssertIsExpectedAsync(decompiledText, _output); } [Theory] - [InlineData("class C { static int F = 1; }")] - [InlineData("class C { static C() {} }")] - [InlineData("class C { class N { static N() {} } }")] + [InlineData("class C { static int F = ((Func)(() => throw new ConstructorRanException()))(); }")] + [InlineData("class C { static C() => throw new ConstructorRanException(); }")] + [InlineData("class C { class N { static N() => throw new ConstructorRanException(); } }")] public async Task SlowUpdate_ReturnsNotSupportedError_ForStaticConstructors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); + var driver = TestEnvironment.NewDriver().SetText(@$" + using System; + public class ConstructorRanException: Exception {{}} + + {code} + "); await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.JitAsm); - await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); + var (result, exception) = await RecordExceptionOrResultAsync(() => driver.SendSlowUpdateAsync()); + + Assert.Empty(result?.JoinErrors() ?? ""); + Assert.IsType(exception); + } + + [Theory] + [InlineData("class C { [ModuleInitializer] public static void I() => throw new InitializerRanException(); }")] + [InlineData("class C { public class N { [ModuleInitializer] public static void I() => throw new InitializerRanException(); } }")] + public async Task SlowUpdate_ReturnsNotSupportedError_ForModuleInitializers(string code) { + var driver = TestEnvironment.NewDriver().SetText(@$" + using System; + using System.Runtime.CompilerServices; + + public class InitializerRanException: Exception {{}} + + namespace System.Runtime.CompilerServices {{ + public class ModuleInitializerAttribute : Attribute {{ + }} + }} + + {code} + "); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.JitAsm); + + var (result, exception) = await RecordExceptionOrResultAsync(() => driver.SendSlowUpdateAsync()); + + Assert.Empty(result?.JoinErrors() ?? ""); + Assert.IsType(exception); + } + + private async Task<(T? result, Exception? exception)> RecordExceptionOrResultAsync(Func> callAsync) { + try { + return (await callAsync(), null); + } + catch (Exception ex) { + return (default, ex); + } } } } diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Ast/EmptyType.fs b/source/NetFramework/Tests/Decompilation/TestCode/Ast/EmptyType.fs index 58d0ff6ef..1fb65e0a5 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Ast/EmptyType.fs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Ast/EmptyType.fs @@ -7,6 +7,63 @@ type Empty = class end "kind": "ParsedImplFileInput", "type": "node", "children": [ + { + "kind": "SynModuleOrNamespace", + "type": "node", + "range": "0-22", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "_", + "range": "0-0" + }, + { + "kind": "SynModuleDecl.Types", + "type": "node", + "range": "0-22", + "children": [ + { + "kind": "SynTypeDefn", + "type": "node", + "range": "5-22", + "children": [ + { + "kind": "SynComponentInfo", + "property": "typeInfo", + "type": "node", + "range": "5-10", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "Empty", + "range": "5-10" + } + ] + }, + { + "kind": "SynTypeDefnRepr.ObjectModel", + "property": "typeRepr", + "type": "node", + "range": "13-22", + "children": [ + { + "kind": "SynTypeDefnKind", + "property": "kind", + "type": "node", + "value": "Class" + } + ] + } + ] + } + ] + } + ] + }, { "kind": "SynModuleOrNamespace", "type": "node", diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs b/source/NetFramework/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs index 1fb92d4ea..fef785f47 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs @@ -23,15 +23,10 @@ b" "range": "0-0" }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "0-1", "children": [ - { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, { "kind": "SynExpr.Const", "property": "expr", @@ -49,15 +44,10 @@ b" ] }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "3-6", "children": [ - { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, { "kind": "SynExpr.Const", "property": "expr", @@ -75,15 +65,95 @@ b" ] }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "8-14", "children": [ { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "8-14", + "children": [ + { + "kind": "SynConst.String", + "property": "constant", + "type": "token", + "value": "\"a\r\nb\"", + "children": [ + { + "kind": "SynStringKind", + "property": "synStringKind", + "type": "value", + "value": "Regular" + } + ] + } + ] + } + ] + } + ] + }, + { + "kind": "SynModuleOrNamespace", + "type": "node", + "range": "0-14", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "_", + "range": "0-0" + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "0-1", + "children": [ + { + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "0-1", + "children": [ + { + "kind": "SynConst.Int32", + "property": "constant", + "type": "token", + "value": "1" + } + ] + } + ] + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "3-6", + "children": [ + { + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "3-6", + "children": [ + { + "kind": "SynConst.Char", + "property": "constant", + "type": "token", + "value": "'c'" + } + ] + } + ] + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "8-14", + "children": [ { "kind": "SynExpr.Const", "property": "expr", diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs similarity index 57% rename from source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs index 2c12eae59..2d8b958b8 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs @@ -8,7 +8,7 @@ public void Baz() { } } -#=> +/* cs using System; using System.Diagnostics; @@ -16,6 +16,7 @@ public void Baz() { using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -23,6 +24,30 @@ public void Baz() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class Foo { public static explicit operator Nullable(Foo foo) @@ -36,4 +61,6 @@ public void Baz() { Nullable num = (Nullable)(Foo)null; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs similarity index 56% rename from source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs index 59986be7e..e5d76e56f 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs @@ -6,13 +6,15 @@ public void M(string n) { } } -#=> +/* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -20,6 +22,30 @@ public void M(string n) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { public void M(string n) @@ -28,4 +54,6 @@ public void M(string n) { } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs similarity index 54% rename from source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs index da361a8a9..e8e955c66 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Constructor.BaseCall.cs @@ -9,13 +9,15 @@ public MyClass(string name) : base(name) { } } -#=> +/* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -23,6 +25,30 @@ public MyClass(string name) : base(name) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class MyBase { public MyBase(string name) @@ -35,4 +61,6 @@ public MyClass(string name) : base(name) { } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/EmptyType.fs b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/EmptyType.fs index 927d8e2a1..9ea940bb0 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/EmptyType.fs +++ b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/EmptyType.fs @@ -37,6 +37,18 @@ type Empty = class end .class private auto ansi abstract sealed '.$_' extends [mscorlib]System.Object { + // Methods + .method public static + void main@ () cil managed + { + // Method begins at RVA 0x2050 + // Code size 1 (0x1) + .maxstack 8 + .entrypoint + + IL_0000: ret + } // end of method $_::main@ + } // end of class .$_ *) \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs similarity index 86% rename from source/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs index c8e7fb69a..ac958706e 100644 --- a/source/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs @@ -3,7 +3,7 @@ open System type C() = member __.notNull x = not (isNull x) -#=> +(* cs using System; using System.Reflection; @@ -32,5 +32,10 @@ namespace { internal static class $_ { + public static void main@() + { + } } -} \ No newline at end of file +} + +*) \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs new file mode 100644 index 000000000..176abb67f --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs @@ -0,0 +1,37 @@ +#if DEBUG + printfn "Debug" +#else + printfn "Release" +#endif + +(* cs + +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.FSharp.Core; + +[assembly: FSharpInterfaceDataVersion(2, 0, 0)] +[assembly: AssemblyVersion("0.0.0.0")] +[CompilationMapping(SourceConstructFlags.Module)] +public static class @_ +{ +} +namespace +{ + internal static class $_ + { + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + [CompilerGenerated] + [DebuggerNonUserCode] + internal static int init@; + + public static void main@() + { + ExtraTopLevelOperators.PrintFormatLine(new PrintfFormat("Debug")); + } + } +} + +*) \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs2cs b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs2cs deleted file mode 100644 index f714f7074..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs2cs +++ /dev/null @@ -1,49 +0,0 @@ -#if DEBUG - printfn "Debug" -#else - printfn "Release" -#endif - -#=> - -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using ; -using Microsoft.FSharp.Core; - -[assembly: FSharpInterfaceDataVersion(2, 0, 0)] -[assembly: AssemblyVersion("0.0.0.0")] -[CompilationMapping(SourceConstructFlags.Module)] -public static class @_ -{ - [CompilationMapping(SourceConstructFlags.Value)] - internal static PrintfFormat format@1 - { - get - { - return $_.format@1; - } - } -} -namespace -{ - internal static class $_ - { - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - internal static readonly PrintfFormat format@1; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - [CompilerGenerated] - [DebuggerNonUserCode] - internal static int init@; - - static $_() - { - format@1 = new PrintfFormat("Debug"); - PrintfModule.PrintFormatLineToTextWriter(Console.Out, @_.format@1); - } - } -} \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs similarity index 83% rename from source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs index 9df9c2fab..9221d8a98 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs @@ -2,7 +2,7 @@ open System type C() = member this.M() = 5 -#=> +(* cs using System; using System.Reflection; @@ -27,5 +27,10 @@ namespace { internal static class $_ { + public static void main@() + { + } } -} \ No newline at end of file +} + +*) \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs2il b/source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs similarity index 52% rename from source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs2il rename to source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs index 84f2744ee..7f5b46c88 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs2il +++ b/source/NetFramework/Tests/Decompilation/TestCode/Finalizer.Exception.cs @@ -5,7 +5,7 @@ public class C { } } -#=> +/* il .assembly _ { @@ -39,6 +39,67 @@ .class private auto ansi '' { } // end of class +.class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2050 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: ret + } // end of method EmbeddedAttribute::.ctor + +} // end of class Microsoft.CodeAnalysis.EmbeddedAttribute + +.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.RefSafetyRulesAttribute + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 02 00 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + // Fields + .field public initonly int32 Version + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '' + ) cil managed + { + // Method begins at RVA 0x2058 + // Code size 14 (0xe) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 System.Runtime.CompilerServices.RefSafetyRulesAttribute::Version + IL_000d: ret + } // end of method RefSafetyRulesAttribute::.ctor + +} // end of class System.Runtime.CompilerServices.RefSafetyRulesAttribute + .class public auto ansi beforefieldinit C extends [mscorlib]System.Object { @@ -47,7 +108,7 @@ .method family hidebysig virtual instance void Finalize () cil managed { .override method instance void [mscorlib]System.Object::Finalize() - // Method begins at RVA 0x2050 + // Method begins at RVA 0x2068 // Code size 13 (0xd) .maxstack 1 @@ -69,7 +130,7 @@ .maxstack 1 .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { - // Method begins at RVA 0x207c + // Method begins at RVA 0x2094 // Code size 7 (0x7) .maxstack 8 @@ -78,4 +139,6 @@ .maxstack 8 IL_0006: ret } // end of method C::.ctor -} // end of class C \ No newline at end of file +} // end of class C + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs similarity index 57% rename from source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs index b74263777..9e1246fee 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Goto.TryWhile.cs @@ -10,13 +10,15 @@ void M() { } } -#=> +/* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -24,6 +26,30 @@ void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { private void M() @@ -41,4 +67,6 @@ private void M() } } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs new file mode 100644 index 000000000..e2d42a8c6 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs @@ -0,0 +1,28 @@ +static class C { + static int M(int[] x) { + return x[0]; + } +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C.M(Int32[]) + L0000: sub rsp, 0x28 + L0004: cmp dword [rcx+0x8], 0x0 + L0008: jbe L0012 + L000a: mov eax, [rcx+0x10] + L000d: add rsp, 0x28 + L0011: ret + L0012: call 0x + L0017: int3 + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm deleted file mode 100644 index f880bc620..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm +++ /dev/null @@ -1,17 +0,0 @@ -static class C { - static int M(int[] x) { - return x[0]; - } -} - -#=> - -; Desktop CLR on x86 - -C.M(Int32[]) - L0000: cmp dword [ecx+0x4], 0x0 - L0004: jbe L000a - L0006: mov eax, [ecx+0x8] - L0009: ret - L000a: call 0x - L000f: int3 \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs new file mode 100644 index 000000000..5c8383b6c --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs @@ -0,0 +1,197 @@ +// https://github.com/ashmind/SharpLab/issues/39#issuecomment-298152571 +using System; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; + +static class C { + static int M(int x) { + return Foo(x + 0x12345).Result; + } + + static async Task Foo(int x) { + return x; + } +} + +/* asm + +; Core CLR on x64 + +C.M(Int32) + L0000: push rdi + L0001: push rsi + L0002: sub rsp, 0x28 + L0006: add ecx, 0x12345 + L000c: call C.Foo(Int32) + L0011: mov rsi, rax + L0014: mov ecx, [rsi+0x34] + L0017: and ecx, 0x + L001d: cmp ecx, 0x + L0023: jne short L002a + L0025: mov eax, [rsi+0x38] + L0028: jmp short L0077 + L002a: test dword ptr [rsi+0x34], 0x + L0031: jne short L0044 + L0033: mov rcx, rsi + L0036: xor r8d, r8d + L0039: mov edx, 0x + L003e: call qword ptr [0x] + L0044: mov rcx, rsi + L0047: call qword ptr [0x] + L004d: mov ecx, [rsi+0x34] + L0050: and ecx, 0x + L0056: cmp ecx, 0x + L005c: je short L0074 + L005e: mov rcx, rsi + L0061: mov edx, 1 + L0066: call qword ptr [0x] + L006c: mov rdi, rax + L006f: test rdi, rdi + L0072: jne short L007e + L0074: mov eax, [rsi+0x38] + L0077: add rsp, 0x28 + L007b: pop rsi + L007c: pop rdi + L007d: ret + L007e: mov rcx, rsi + L0081: call qword ptr [0x] + L0087: mov rcx, rdi + L008a: call 0x + L008f: int3 + +C.Foo(Int32) + L0000: sub rsp, 0x38 + L0004: xor eax, eax + L0006: mov [rsp+0x28], rax + L000b: mov [rsp+0x30], rax + L0010: xor eax, eax + L0012: mov [rsp+0x30], rax + L0017: mov [rsp+0x2c], ecx + L001b: mov dword ptr [rsp+0x28], 0x + L0023: lea rcx, [rsp+0x28] + L0028: call System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[C+d__1, _]](d__1 ByRef) + L002d: mov rax, [rsp+0x30] + L0032: test rax, rax + L0035: je short L003c + L0037: add rsp, 0x38 + L003b: ret + L003c: lea rcx, [rsp+0x30] + L0041: call qword ptr [0x] + L0047: jmp short L0037 + +C+d__1.MoveNext() + L0000: push rbp + L0001: push rdi + L0002: push rsi + L0003: sub rsp, 0x30 + L0007: lea rbp, [rsp+0x40] + L000c: mov [rbp-0x20], rsp + L0010: mov [rbp+0x10], rcx + L0014: mov esi, [rcx+4] + L0017: mov dword ptr [rcx], 0x + L001d: lea rdi, [rcx+8] + L0021: cmp qword ptr [rdi], 0 + L0025: jne short L007f + L0027: mov ecx, esi + L0029: lea eax, [rcx+1] + L002c: cmp eax, 0xa + L002f: jb short L0057 + L0031: mov rcx, 0x + L003b: call 0x + L0040: mov rdx, rax + L0043: mov dword ptr [rdx+0x34], 0x + L004a: mov [rdx+0x38], esi + L004d: mov rcx, rdi + L0050: call 0x + L0055: jmp short L0077 + L0057: mov rax, 0x + L0061: mov rax, [rax] + L0064: lea edx, [rcx+1] + L0067: cmp edx, [rax+8] + L006a: jae short L008c + L006c: inc ecx + L006e: mov ecx, ecx + L0070: mov rdx, [rax+rcx*8+0x10] + L0075: jmp short L004d + L0077: add rsp, 0x30 + L007b: pop rsi + L007c: pop rdi + L007d: pop rbp + L007e: ret + L007f: mov rcx, [rdi] + L0082: mov edx, esi + L0084: call qword ptr [0x] + L008a: jmp short L0077 + L008c: call 0x + L0091: int3 + L0092: push rbp + L0093: push rdi + L0094: push rsi + L0095: sub rsp, 0x30 + L0099: mov rbp, [rcx+0x20] + L009d: mov [rsp+0x20], rbp + L00a2: lea rbp, [rbp+0x40] + L00a6: mov rcx, [rbp+0x10] + L00aa: mov dword ptr [rcx], 0x + L00b0: add rcx, 8 + L00b4: call qword ptr [0x] + L00ba: lea rax, [L0077] + L00c1: add rsp, 0x30 + L00c5: pop rsi + L00c6: pop rdi + L00c7: pop rbp + L00c8: ret + +C+d__1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine) + L0000: sub rsp, 0x28 + L0004: mov rcx, [rcx+8] + L0008: test rdx, rdx + L000b: je short L0017 + L000d: test rcx, rcx + L0010: jne short L0023 + L0012: add rsp, 0x28 + L0016: ret + L0017: mov ecx, 0x3d + L001c: call qword ptr [0x] + L0022: int3 + L0023: mov ecx, 0x27 + L0028: call qword ptr [0x] + L002e: int3 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.NullableAttribute..ctor(Byte) + L0000: push rdi + L0001: push rsi + L0002: sub rsp, 0x28 + L0006: mov rsi, rcx + L0009: mov edi, edx + L000b: mov rcx, 0x + L0015: mov edx, 1 + L001a: call 0x + L001f: mov [rax+0x10], dil + L0023: lea rcx, [rsi+8] + L0027: mov rdx, rax + L002a: call 0x + L002f: nop + L0030: add rsp, 0x28 + L0034: pop rsi + L0035: pop rdi + L0036: ret + +System.Runtime.CompilerServices.NullableAttribute..ctor(Byte[]) + L0000: lea rcx, [rcx+8] + L0004: call 0x + L0009: nop + L000a: ret + +System.Runtime.CompilerServices.NullableContextAttribute..ctor(Byte) + L0000: mov [rcx+8], dl + L0003: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+8], edx + L0003: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm deleted file mode 100644 index 740de0a83..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm +++ /dev/null @@ -1,113 +0,0 @@ -// https://github.com/ashmind/SharpLab/issues/39#issuecomment-298152571 -using System; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; - -static class C { - static int M(int x) { - return Foo(x + 0x12345).Result; - } - - static async Task Foo(int x) { - return x; - } -} - -#=> - -; Desktop CLR on x86 - -C.M(Int32) - L0000: push ebp - L0001: mov ebp, esp - L0003: add ecx, 0x12345 - L0009: call dword [0x] - L000f: mov ecx, eax - L0011: cmp [ecx], ecx - L0013: call System.Threading.Tasks.Task`1[[System.Int32, mscorlib]].get_Result() - L0018: pop ebp - L0019: ret - -C.Foo(Int32) - L0000: push ebp - L0001: mov ebp, esp - L0003: push edi - L0004: push esi - L0005: sub esp, 0x20 - L0008: mov esi, ecx - L000a: lea edi, [ebp-0x28] - L000d: mov ecx, 0x8 - L0012: xor eax, eax - L0014: rep stosd - L0016: mov ecx, esi - L0018: mov edx, ecx - L001a: lea edi, [ebp-0x28] - L001d: xor eax, eax - L001f: xorps xmm0, xmm0 - L0022: movq [edi], xmm0 - L0026: add edi, 0x8 - L0029: stosd - L002a: lea edi, [ebp-0x28] - L002d: xorps xmm0, xmm0 - L0030: movq [edi], xmm0 - L0034: add edi, 0x8 - L0037: stosd - L0038: lea edi, [ebp-0x14] - L003b: lea esi, [ebp-0x28] - L003e: call 0x - L0043: call 0x - L0048: call 0x - L004d: mov [ebp-0x18], edx - L0050: mov dword [ebp-0x1c], 0x - L0057: lea ecx, [ebp-0x14] - L005a: lea edx, [ebp-0x1c] - L005d: call dword [0x] - L0063: lea ecx, [ebp-0x14] - L0066: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].get_Task() - L006b: lea esp, [ebp-0x8] - L006e: pop esi - L006f: pop edi - L0070: pop ebp - L0071: ret - -C+d__1.MoveNext() - L0000: push ebp - L0001: mov ebp, esp - L0003: sub esp, 0x18 - L0006: xor eax, eax - L0008: mov [ebp-0x14], eax - L000b: mov [ebp-0x10], eax - L000e: mov [ebp-0xc], eax - L0011: mov [ebp-0x8], eax - L0014: mov [ebp-0x18], ecx - L0017: mov edx, [ebp-0x18] - L001a: mov eax, [edx+0x4] - L001d: jmp L003d - L001f: mov edx, eax - L0021: mov eax, [ebp-0x18] - L0024: mov dword [eax], 0x - L002a: cmp [eax], al - L002c: mov ecx, eax - L002e: add ecx, 0x8 - L0031: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].SetException(System.Exception) - L0036: call 0x - L003b: jmp L0051 - L003d: mov dword [edx], 0x - L0043: cmp [edx], al - L0045: add edx, 0x8 - L0048: mov ecx, edx - L004a: mov edx, eax - L004c: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, mscorlib]].SetResult(Int32) - L0051: mov esp, ebp - L0053: pop ebp - L0054: ret - -C+d__1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine) - L0000: cmp [ecx], al - L0002: add ecx, 0x8 - L0005: mov eax, ecx - L0007: cmp [eax], al - L0009: add eax, 0x4 - L000c: mov ecx, eax - L000e: call System.Runtime.CompilerServices.AsyncMethodBuilderCore.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine) - L0013: ret \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs new file mode 100644 index 000000000..fa7b6cd5d --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs @@ -0,0 +1,22 @@ +using System; +static class C { + static void M() => Console.WriteLine("test"); +} + +/* asm + +; Core CLR on x64 + +C.M() + L0000: mov rcx, 0x + L000a: mov rcx, [rcx] + L000d: jmp qword ptr [0x] + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+8], edx + L0003: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm deleted file mode 100644 index 1cd422a28..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm +++ /dev/null @@ -1,13 +0,0 @@ -using System; -static class C { - static void M() => Console.WriteLine("test"); -} - -#=> - -; Desktop CLR on x86 - -C.M() - L0000: mov ecx, [0x] - L0006: call System.Console.WriteLine(System.String) - L000b: ret \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs new file mode 100644 index 000000000..2ce188725 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs @@ -0,0 +1,30 @@ +delegate void D(); + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Cannot produce JIT assembly for runtime-implemented method. + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Cannot produce JIT assembly for runtime-implemented method. + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Cannot produce JIT assembly for runtime-implemented method. + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Cannot produce JIT assembly for runtime-implemented method. + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm deleted file mode 100644 index 51a9c3419..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm +++ /dev/null @@ -1,17 +0,0 @@ -delegate void D(); - -#=> - -; Desktop CLR on x86 - -D..ctor(System.Object, IntPtr) - ; Cannot produce JIT assembly for runtime-implemented method. - -D.Invoke() - ; Cannot produce JIT assembly for runtime-implemented method. - -D.BeginInvoke(System.AsyncCallback, System.Object) - ; Cannot produce JIT assembly for runtime-implemented method. - -D.EndInvoke(System.IAsyncResult) - ; Cannot produce JIT assembly for runtime-implemented method. \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/DllImport.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/DllImport.cs index e6b336015..5551171a0 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/DllImport.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/DllImport.cs @@ -8,9 +8,17 @@ public static class NativeMethods /* asm -; Desktop CLR on x86 +; Desktop CLR on x64 -NativeMethods.GetLastError() +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +Unknown (0x) + ; Method signature was not found -- please report this issue. ; Cannot produce JIT assembly for a P/Invoke method. */ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs index 8f23d9f6d..8298097df 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs @@ -11,29 +11,29 @@ static T M() { /* asm -; Desktop CLR on x86 +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret C`1[[System.Int32, mscorlib]].M() L0000: xor eax, eax L0002: ret C`1[[System.Decimal, mscorlib]].M() - L0000: push edi - L0001: push esi - L0002: xor eax, eax - L0004: xor edx, edx - L0006: xor esi, esi - L0008: xor edi, edi - L000a: mov [ecx], eax - L000c: mov [ecx+0x4], edx - L000f: mov [ecx+0x8], esi - L0012: mov [ecx+0xc], edi - L0015: pop esi - L0016: pop edi - L0017: ret - -C`1[[System.__Canon, mscorlib]].M() - L0000: xor eax, eax - L0002: ret + L0000: vzeroupper + L0003: vxorps xmm0, xmm0, xmm0 + L0008: vmovdqu [rcx], xmm0 + L000d: mov rax, rcx + L0010: ret + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs new file mode 100644 index 000000000..27d417353 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs @@ -0,0 +1,38 @@ +using SharpLab.Runtime; +static class C { + [JitGeneric(typeof(int))] + [JitGeneric(typeof(decimal))] + [JitGeneric(typeof(string))] + static T M() { + return default(T); + } +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C.M[[System.Int32, mscorlib]]() + L0000: xor eax, eax + L0002: ret + +C.M[[System.Decimal, mscorlib]]() + L0000: vzeroupper + L0003: vxorps xmm0, xmm0, xmm0 + L0008: vmovdqu [rcx], xmm0 + L000d: mov rax, rcx + L0010: ret + +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm deleted file mode 100644 index e80922c84..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm +++ /dev/null @@ -1,36 +0,0 @@ -using SharpLab.Runtime; -static class C { - [JitGeneric(typeof(int))] - [JitGeneric(typeof(decimal))] - [JitGeneric(typeof(string))] - static T M() { - return default(T); - } -} - -#=> - -; Desktop CLR on x86 - -C.M[[System.Int32, mscorlib]]() - L0000: xor eax, eax - L0002: ret - -C.M[[System.Decimal, mscorlib]]() - L0000: push edi - L0001: push esi - L0002: xor eax, eax - L0004: xor edx, edx - L0006: xor esi, esi - L0008: xor edi, edi - L000a: mov [ecx], eax - L000c: mov [ecx+0x4], edx - L000f: mov [ecx+0x8], esi - L0012: mov [ecx+0xc], edi - L0015: pop esi - L0016: pop edi - L0017: ret - -C.M[[System.String, mscorlib]]() - ; Failed to find JIT output for generic method (reference types?). - ; If you know a solution, please comment at https://github.com/ashmind/SharpLab/issues/99. \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs index bbb963b5d..6e371476d 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs @@ -12,22 +12,32 @@ static class N { /* asm -; Desktop CLR on x86 +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret C`1+N`1[[System.Int32, mscorlib],[System.Int32, mscorlib]].M(Int32) L0000: xor eax, eax L0002: ret -C`1+N`1[[System.Int32, mscorlib],[System.__Canon, mscorlib]].M(System.__Canon) - L0000: xor eax, eax - L0002: ret +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. -C`1+N`1[[System.__Canon, mscorlib],[System.Int32, mscorlib]].M(Int32) - L0000: xor eax, eax - L0002: ret +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. -C`1+N`1[[System.__Canon, mscorlib],[System.__Canon, mscorlib]].M(System.__Canon) - L0000: xor eax, eax - L0002: ret +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. - */ \ No newline at end of file +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs index 2eea08674..b838b1638 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs @@ -10,14 +10,22 @@ static class N { /* asm -; Desktop CLR on x86 +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret C+N`1[[System.Int32, mscorlib]].get_M() L0000: xor eax, eax L0002: ret -C+N`1[[System.__Canon, mscorlib]].get_M() - L0000: xor eax, eax - L0002: ret +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs index 6a4ffdd3d..17ee21591 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs @@ -10,14 +10,22 @@ static class N { /* asm -; Desktop CLR on x86 +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret C`1+N[[System.Int32, mscorlib]].M() L0000: xor eax, eax L0002: ret -C`1+N[[System.__Canon, mscorlib]].M() - L0000: xor eax, eax - L0002: ret +Unknown (0x) + ; Method signature was not found -- please report this issue. + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs similarity index 63% rename from source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm rename to source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs index dbabc17cb..33f4e4321 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs @@ -16,26 +16,39 @@ static void M() {} } } -#=> +/* asm -; Core CLR on amd64 +; Desktop CLR on x64 -C`1.M() +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +Unknown (0x) + ; Method signature was not found -- please report this issue. ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. -C`1+N.M() +Unknown (0x) + ; Method signature was not found -- please report this issue. ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. -C.M() +Unknown (0x) + ; Method signature was not found -- please report this issue. ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. -C+N`1.M() +Unknown (0x) + ; Method signature was not found -- please report this issue. ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. - ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. \ No newline at end of file + ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs new file mode 100644 index 000000000..7d56a4ab4 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs @@ -0,0 +1,34 @@ +// https://github.com/ashmind/SharpLab/issues/229 +public class C +{ + public int M(int a) { + back: + a += 1; + if (a == 0) + goto back; + return a; + } +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C..ctor() + L0000: ret + +C.M(Int32) + L0000: inc edx + L0002: test edx, edx + L0004: jz L0000 + L0006: mov eax, edx + L0008: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm deleted file mode 100644 index c0726a105..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm +++ /dev/null @@ -1,27 +0,0 @@ -// https://github.com/ashmind/SharpLab/issues/229 -public class C -{ - public int M(int a) { - back: - a += 1; - if (a == 0) - goto back; - return a; - } -} - -#=> - -; Desktop CLR on x86 - -C..ctor() - L0000: ret - -C.M(Int32) - L0000: push ebp - L0001: mov ebp, esp - L0003: mov eax, edx - L0005: inc eax - L0006: jz L0005 - L0008: pop ebp - L0009: ret \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs new file mode 100644 index 000000000..a2fd652eb --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs @@ -0,0 +1,25 @@ +// https://github.com/ashmind/SharpLab/issues/458 +using System; +public static class C { + public static double M(double a, double b, double c) { + return Math.FusedMultiplyAdd(a, b, c); + } +} + +/* asm + +; Core CLR on x64 + +C.M(Double, Double, Double) + L0000: vzeroupper + L0003: vfmadd213sd xmm0, xmm1, xmm2 + L0008: ret + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+8], edx + L0003: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs new file mode 100644 index 000000000..200c98184 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs @@ -0,0 +1,22 @@ +using System.Runtime.CompilerServices; + +public static class C { + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void M(); +} + +/* asm + +; Core CLR on x64 + +C.M() + ; Cannot produce JIT assembly for an internal call method. + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+8], edx + L0003: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs new file mode 100644 index 000000000..76dc07b4b --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs @@ -0,0 +1,26 @@ +static class C { + static int M(bool x) { + return x ? 1 : 2; + } +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C.M(Boolean) + L0000: test cl, cl + L0002: jnz L000a + L0004: mov eax, 0x2 + L0009: ret + L000a: mov eax, 0x1 + L000f: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm deleted file mode 100644 index 7e055fc53..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm +++ /dev/null @@ -1,17 +0,0 @@ -static class C { - static int M(bool x) { - return x ? 1 : 2; - } -} - -#=> - -; Desktop CLR on x86 - -C.M(Boolean) - L0000: and ecx, 0xff - L0006: jnz L000e - L0008: mov eax, 0x2 - L000d: ret - L000e: mov eax, 0x1 - L0013: ret \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs new file mode 100644 index 000000000..2a4a89163 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs @@ -0,0 +1,22 @@ +static class C { + static class N { + static int M() => 0x12345; + } +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C+N.M() + L0000: mov eax, 0x12345 + L0005: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm deleted file mode 100644 index 5a990b42b..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm +++ /dev/null @@ -1,13 +0,0 @@ -static class C { - static class N { - static int M() => 0x12345; - } -} - -#=> - -; Desktop CLR on x86 - -C+N.M() - L0000: mov eax, 0x12345 - L0005: ret \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs new file mode 100644 index 000000000..773069f52 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs @@ -0,0 +1,20 @@ +static class C { + static int M() => 0x12345; +} + +/* asm + +; Desktop CLR on x64 + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+0x8], edx + L0003: ret + +C.M() + L0000: mov eax, 0x12345 + L0005: ret + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Vectors.NoAvx2.cs b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs similarity index 61% rename from source/Tests/Decompilation/TestCode/JitAsm/Vectors.NoAvx2.cs rename to source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs index 75ca6293f..c20433191 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Vectors.NoAvx2.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs @@ -1,30 +1,37 @@ -// https://github.com/ashmind/SharpLab/issues/487 -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; - -public class C -{ - public int M(Vector256 vector) { - var add1 = Sse2.Add(vector.GetLower(), vector.GetUpper()); - return add1.ToScalar(); - } -} - -/* asm - -; Core CLR on amd64 - -C..ctor() - L0000: ret - -C.M(System.Runtime.Intrinsics.Vector256`1) - L0000: vzeroupper - L0003: vmovupd ymm0, [rdx] - L0007: vmovaps ymm1, ymm0 - L000b: vextractf128 xmm1, ymm1, 1 - L0011: vpaddd xmm0, xmm0, xmm1 - L0015: vmovd eax, xmm0 - L0019: vzeroupper - L001c: ret - +// https://github.com/ashmind/SharpLab/issues/487 +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +public class C +{ + public int M(Vector256 vector) { + var add1 = Sse2.Add(vector.GetLower(), vector.GetUpper()); + return add1.ToScalar(); + } +} + +/* asm + +; Core CLR on x64 + +C..ctor() + L0000: ret + +C.M(System.Runtime.Intrinsics.Vector256`1) + L0000: vzeroupper + L0003: vmovupd ymm0, [rdx] + L0007: vmovdqu ymm1, [rdx] + L000b: vextracti128 xmm0, ymm0, 1 + L0011: vpaddd xmm0, xmm1, xmm0 + L0015: vmovd eax, xmm0 + L0019: vzeroupper + L001c: ret + +Microsoft.CodeAnalysis.EmbeddedAttribute..ctor() + L0000: ret + +System.Runtime.CompilerServices.RefSafetyRulesAttribute..ctor(Int32) + L0000: mov [rcx+8], edx + L0003: ret + */ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs similarity index 71% rename from source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs index 8ad7170e7..dd8c7ea31 100644 --- a/source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs @@ -7,7 +7,7 @@ public void M() { } } -#=> +/* cs using System; using System.Diagnostics; @@ -16,6 +16,7 @@ public void M() { using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -23,6 +24,30 @@ public void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { [Serializable] @@ -57,4 +82,6 @@ private struct __StaticArrayInitTypeSize=16 } internal static readonly __StaticArrayInitTypeSize=16 81C1A5A2F482E82CA2C66653482AB24E6D90944BF183C8164E8F8F8D72DB60DB/* Not supported: data(01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00) */; -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs similarity index 62% rename from source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs index ef17abae5..89a24039d 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs @@ -5,7 +5,7 @@ public int M(Point p) { } } -#=> +/* cs using System; using System.Diagnostics; @@ -13,6 +13,7 @@ public int M(Point p) { using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -20,6 +21,30 @@ public int M(Point p) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class Point { [CompilerGenerated] @@ -44,4 +69,6 @@ public int M(Point p) Nullable num = ((p != null) ? new Nullable(p.X) : null); return num.GetValueOrDefault(); } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs similarity index 57% rename from source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs index 9dddcbc5d..1765e4686 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs @@ -5,7 +5,7 @@ public bool M(DateTime? d) { } } -#=> +/* cs using System; using System.Diagnostics; @@ -13,6 +13,7 @@ public bool M(DateTime? d) { using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -20,6 +21,30 @@ public bool M(DateTime? d) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { public bool M(Nullable d) @@ -32,4 +57,6 @@ public bool M(Nullable d) } return dateTime.GetValueOrDefault() > now; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs b/source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs new file mode 100644 index 000000000..194d04440 --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs @@ -0,0 +1,54 @@ +public class C { + public void M(decimal d = 5.0m) { + } +} + +/* cs + +using System; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security; +using System.Security.Permissions; +using Microsoft.CodeAnalysis; + +[assembly: CompilationRelaxations(8)] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] +[assembly: AssemblyVersion("0.0.0.0")] +[module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} +public class C +{ + public void M([Optional][DecimalConstant(1, 0, 0u, 0u, 50u)] decimal d) + { + } +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs similarity index 56% rename from source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs index 36e06da96..1dded18aa 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs @@ -9,13 +9,15 @@ public string M() { } } -#=> +/* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -23,10 +25,36 @@ public string M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { public string M() { return "Debug"; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs b/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs new file mode 100644 index 000000000..dd0e1dd3a --- /dev/null +++ b/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs @@ -0,0 +1,117 @@ +public class Simple { +} + +/* il + +.assembly _ +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( + 01 00 08 00 00 00 00 00 + ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( + 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 + 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 + ) + .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( + 01 00 02 00 00 00 00 00 + ) + .permissionset reqmin = ( + 2e 01 80 84 53 79 73 74 65 6d 2e 53 65 63 75 72 + 69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e + 53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69 + 6f 6e 41 74 74 72 69 62 75 74 65 2c 20 6d 73 63 + 6f 72 6c 69 62 2c 20 56 65 72 73 69 6f 6e 3d 34 + 2e 30 2e 30 2e 30 2c 20 43 75 6c 74 75 72 65 3d + 6e 65 75 74 72 61 6c 2c 20 50 75 62 6c 69 63 4b + 65 79 54 6f 6b 65 6e 3d 62 37 37 61 35 63 35 36 + 31 39 33 34 65 30 38 39 15 01 54 02 10 53 6b 69 + 70 56 65 72 69 66 69 63 61 74 69 6f 6e 01 + ) + .hash algorithm 0x // SHA1 + .ver 0:0:0:0 +} + +.class private auto ansi '' +{ +} // end of class + +.class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2050 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: ret + } // end of method EmbeddedAttribute::.ctor + +} // end of class Microsoft.CodeAnalysis.EmbeddedAttribute + +.class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.RefSafetyRulesAttribute + extends [mscorlib]System.Attribute +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 02 00 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + // Fields + .field public initonly int32 Version + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + int32 '' + ) cil managed + { + // Method begins at RVA 0x2058 + // Code size 14 (0xe) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Attribute::.ctor() + IL_0006: ldarg.0 + IL_0007: ldarg.1 + IL_0008: stfld int32 System.Runtime.CompilerServices.RefSafetyRulesAttribute::Version + IL_000d: ret + } // end of method RefSafetyRulesAttribute::.ctor + +} // end of class System.Runtime.CompilerServices.RefSafetyRulesAttribute + +.class public auto ansi beforefieldinit Simple + extends [mscorlib]System.Object +{ + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2067 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Simple::.ctor + +} // end of class Simple + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs2il b/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs2il deleted file mode 100644 index 3899bacf0..000000000 --- a/source/NetFramework/Tests/Decompilation/TestCode/Simple.cs2il +++ /dev/null @@ -1,54 +0,0 @@ -public class Simple { -} - -#=> - -.assembly _ -{ - .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( - 01 00 08 00 00 00 00 00 - ) - .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( - 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 - 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 - ) - .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( - 01 00 02 00 00 00 00 00 - ) - .permissionset reqmin = ( - 2e 01 80 84 53 79 73 74 65 6d 2e 53 65 63 75 72 - 69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e - 53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69 - 6f 6e 41 74 74 72 69 62 75 74 65 2c 20 6d 73 63 - 6f 72 6c 69 62 2c 20 56 65 72 73 69 6f 6e 3d 34 - 2e 30 2e 30 2e 30 2c 20 43 75 6c 74 75 72 65 3d - 6e 65 75 74 72 61 6c 2c 20 50 75 62 6c 69 63 4b - 65 79 54 6f 6b 65 6e 3d 62 37 37 61 35 63 35 36 - 31 39 33 34 65 30 38 39 15 01 54 02 10 53 6b 69 - 70 56 65 72 69 66 69 63 61 74 69 6f 6e 01 - ) - .hash algorithm 0x // SHA1 - .ver 0:0:0:0 -} - -.class private auto ansi '' -{ -} // end of class - -.class public auto ansi beforefieldinit Simple - extends [mscorlib]System.Object -{ - // Methods - .method public hidebysig specialname rtspecialname - instance void .ctor () cil managed - { - // Method begins at RVA 0x2050 - // Code size 7 (0x7) - .maxstack 8 - - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Simple::.ctor - -} // end of class Simple \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs b/source/NetFramework/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs index 8f44b4cc2..3238cd206 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs @@ -1,5 +1,7 @@ -public class C { - public void M() { +public class C +{ + public void M() + { string one = $"This {1} That"; string two = $"This {one} That"; } @@ -7,11 +9,13 @@ public void M() { /* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -19,6 +23,30 @@ public void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { public void M() diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs similarity index 58% rename from source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs index a53197774..342b837a2 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs @@ -3,14 +3,16 @@ internal unsafe struct MyBuffer public fixed char fixedBuffer[128]; } -#=> +/* cs +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -18,6 +20,30 @@ internal unsafe struct MyBuffer [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} internal struct MyBuffer { [StructLayout(LayoutKind.Sequential, Size = 256)] @@ -30,4 +56,6 @@ public struct e__FixedBuffer [FixedBuffer(typeof(char), 128)] public e__FixedBuffer fixedBuffer; -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs2cs b/source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs similarity index 62% rename from source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs2cs rename to source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs index a797f4d50..32768dd9e 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs2cs +++ b/source/NetFramework/Tests/Decompilation/TestCode/Using.Simple.cs @@ -5,7 +5,7 @@ public void M() { } } -#=> +/* cs using System; using System.Diagnostics; @@ -14,6 +14,7 @@ public void M() { using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; +using Microsoft.CodeAnalysis; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] @@ -21,6 +22,30 @@ public void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] +namespace Microsoft.CodeAnalysis +{ + [CompilerGenerated] + [Embedded] + internal sealed class EmbeddedAttribute : Attribute + { + } +} +namespace System.Runtime.CompilerServices +{ + [CompilerGenerated] + [Embedded] + [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] + internal sealed class RefSafetyRulesAttribute : Attribute + { + public readonly int Version; + + public RefSafetyRulesAttribute(int P_0) + { + Version = P_0; + } + } +} public class C { public void M() @@ -37,4 +62,6 @@ public void M() } } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/ExecutionTests.cs b/source/NetFramework/Tests/ExecutionTests.cs index 786203cd8..773678627 100644 --- a/source/NetFramework/Tests/ExecutionTests.cs +++ b/source/NetFramework/Tests/ExecutionTests.cs @@ -21,121 +21,125 @@ using SharpLab.Server.Common; using SharpLab.Tests.Internal; -namespace SharpLab.Tests { - public class ExecutionTests { - private readonly ITestOutputHelper _output; - - public ExecutionTests(ITestOutputHelper output) { - _output = output; - - #if DEBUG - var testName = ((ITest) - _output - .GetType() - .GetField("test", BindingFlags.Instance | BindingFlags.NonPublic)! - .GetValue(_output)! - ).DisplayName.Replace(GetType().FullName + ".", ""); - var safeTestName = Regex.Replace(testName, "[^a-zA-Z._-]+", "_"); - if (safeTestName.Length > 100) - safeTestName = safeTestName.Substring(0, 100) + "-" + safeTestName.GetHashCode(); - - var testPath = Path.Combine( - AppContext.BaseDirectory, "assembly-log", - GetType().Name, safeTestName, - "{0}.dll" - ); - //AssemblyLog.Enable(testPath); - #endif - } +namespace SharpLab.Tests; + +public class ExecutionTests { + private readonly ITestOutputHelper _output; + + public ExecutionTests(ITestOutputHelper output) { + _output = output; + + #if DEBUG + var testName = ((ITest) + _output + .GetType() + .GetField("test", BindingFlags.Instance | BindingFlags.NonPublic)! + .GetValue(_output)! + ).DisplayName.Replace(GetType().FullName + ".", ""); + var safeTestName = Regex.Replace(testName, "[^a-zA-Z._-]+", "_"); + if (safeTestName.Length > 100) + safeTestName = safeTestName.Substring(0, 100) + "-" + safeTestName.GetHashCode(); + + var testPath = Path.Combine( + AppContext.BaseDirectory, "assembly-log", + GetType().Name, safeTestName, + "{0}.dll" + ); + //AssemblyLog.Enable(testPath); + #endif + } - [Theory] - [InlineData("Exception.DivideByZero.cs", 4, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Catch.cs", 5, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Catch.When.True.cs", 5, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Catch.When.False.cs", 5, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Finally.cs", 5, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Catch.Finally.cs", 5, "DivideByZeroException")] - [InlineData("Exception.DivideByZero.Catch.Finally.WriteLine.cs", 5, "DivideByZeroException", Optimize.Debug)] - [InlineData("Exception.DivideByZero.Catch.Finally.WriteLine.cs", 5, "DivideByZeroException", Optimize.Release)] - [InlineData("Exception.Throw.New.Finally.cs", 8, "Exception", Optimize.Debug)] - public async Task SlowUpdate_ReportsExceptionInFlow(string resourceName, int expectedLineNumber, string expectedExceptionTypeName, string optimize = Optimize.Debug) { - var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), optimize: optimize); - - var result = await driver.SendSlowUpdateAsync(); - var steps = result.ExtensionResult!.Flow - .Select(s => new { s.Line, s.Exception }) - .ToArray(); - - AssertIsSuccess(result, allowRuntimeException: true); - Assert.Contains(new { Line = expectedLineNumber, Exception = expectedExceptionTypeName }, steps); - } + [Theory] + [InlineData("Exception.DivideByZero.cs", 4, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Catch.cs", 5, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Catch.When.True.cs", 5, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Catch.When.False.cs", 5, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Finally.cs", 5, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Catch.Finally.cs", 5, "DivideByZeroException")] + [InlineData("Exception.DivideByZero.Catch.Finally.WriteLine.cs", 5, "DivideByZeroException", Optimize.Debug)] + [InlineData("Exception.DivideByZero.Catch.Finally.WriteLine.cs", 5, "DivideByZeroException", Optimize.Release)] + [InlineData("Exception.Throw.New.Finally.cs", 8, "Exception", Optimize.Debug)] + public async Task SlowUpdate_ReportsExceptionInFlow(string resourceName, int expectedLineNumber, string expectedExceptionTypeName, string optimize = Optimize.Debug) { + var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), optimize: optimize); + + var result = await driver.SendSlowUpdateAsync(); + var steps = result.ExtensionResult!.Flow + .Select(s => new { s.Line, s.Exception }) + .ToArray(); + + AssertIsSuccess(result, allowRuntimeException: true); + Assert.Contains(new { Line = expectedLineNumber, Exception = (string?)expectedExceptionTypeName }, steps); + } - [Theory] - [InlineData("Notes.Variable.AssignCall.cs")] - [InlineData("Notes.Variable.ManyVariables.cs")] - [InlineData("Notes.Return.Simple.cs")] - [InlineData("Notes.Return.Ref.cs")] - [InlineData("Notes.Return.Ref.Readonly.cs")] - [InlineData("Notes.Loop.For.10Iterations.cs")] - [InlineData("Notes.Variable.MultipleDeclarationsOnTheSameLine.cs")] - [InlineData("Notes.Variable.LongName.cs")] - [InlineData("Notes.Variable.LongValue.cs")] - [InlineData("Notes.Regression.ToStringNull.cs")] // https://github.com/ashmind/SharpLab/issues/380 - public async Task SlowUpdate_ReportsValueNotes(string resourceName) { - var code = LoadCodeFromResource(resourceName); - var expected = code.Split("\r\n").Select((line, index) => new { - Line = index + 1, - Notes = Regex.Match(line, @"//\s+\[(.+)\]\s*$").Groups[1].Value - }).Where(x => !string.IsNullOrEmpty(x.Notes)).ToArray(); - - var driver = await NewTestDriverAsync(code); - - var result = await driver.SendSlowUpdateAsync(); - var steps = result.ExtensionResult?.Flow - .Select(s => new { s.Line, s.Notes }) - .Where(s => !string.IsNullOrEmpty(s.Notes)) - .GroupBy(s => s.Line) - .Select(g => new { Line = g.Key, Notes = string.Join("; ", g.Select(s => s.Notes)) }) - .ToArray(); - - AssertIsSuccess(result); - Assert.Equal(expected, steps); - } + [Theory] + [InlineData("Notes.Variable.AssignCall.cs")] + [InlineData("Notes.Variable.ManyVariables.cs")] + [InlineData("Notes.Return.Simple.cs")] + [InlineData("Notes.Return.Ref.cs")] + [InlineData("Notes.Return.Ref.Readonly.cs")] + [InlineData("Notes.Loop.For.10Iterations.cs")] + [InlineData("Notes.Variable.MultipleDeclarationsOnTheSameLine.cs")] + [InlineData("Notes.Variable.LongName.cs")] + [InlineData("Notes.Variable.LongValue.cs")] + [InlineData("Notes.Regression.ToStringNull.cs")] // https://github.com/ashmind/SharpLab/issues/380 + public async Task SlowUpdate_ReportsValueNotes(string resourceName) { + var code = LoadCodeFromResource(resourceName); + var expected = code.Split("\r\n").Select((line, index) => new { + Line = index + 1, + Notes = Regex.Match(line, @"//\s+\[(.+)\]\s*$").Groups[1].Value + }).Where(x => !string.IsNullOrEmpty(x.Notes)).ToArray(); + + var driver = await NewTestDriverAsync(code); + + var result = await driver.SendSlowUpdateAsync(); + var steps = result.ExtensionResult?.Flow + .Select(s => new { s.Line, s.Notes }) + .Where(s => !string.IsNullOrEmpty(s.Notes)) + .GroupBy(s => s.Line) + .Select(g => new { Line = g.Key, Notes = string.Join("; ", g.Select(s => s.Notes)) }) + .ToArray(); + + AssertIsSuccess(result); + Assert.Equal(expected, steps); + } - [Theory] - [InlineData("void M(int a) {}", "M(1)", 1, "a: 1")] - [InlineData("void M(int a) {\r\n}", "M(1)", 1, "a: 1")] - [InlineData("void M(int a)\r\n{}", "M(1)", 1, "a: 1", true)] - [InlineData("void M(int a\r\n) {}", "M(1)", 1, "a: 1", true)] - [InlineData("void M(\r\nint a\r\n) {}", "M(1)", 2, "a: 1", true)] - [InlineData("void M(int a) {\r\n\r\nConsole.WriteLine();}", "M(1)", 1, "a: 1")] - [InlineData("void M(in int a) {}", "M(1)", 1, "a: 1")] - [InlineData("void M(ref int a) {}", "int x = 1; M(ref x)", 1, "a: 1")] - [InlineData("void M(int a, int b) {}", "M(1, 2)", 1, "a: 1, b: 2")] - [InlineData("void M(int a, out int b) { b = 1; }", "M(1, out var _)", 1, "a: 1")] - [InlineData("void M(int a, int b = 0) {}", "M(1)", 1, "a: 1, b: 0")] - public async Task SlowUpdate_ReportsValueNotes_ForCSharpStaticMethodArguments(string methodCode, string methodCallCode, int expectedMethodLineNumber, string expectedNotes, bool expectedSkipped = false) { - var driver = await NewTestDriverAsync(@" + [Theory] + [InlineData("void M(int a) {}", "M(1)", 1, "a: 1")] + [InlineData("void M(int a) {\r\n}", "M(1)", 1, "a: 1")] + [InlineData("void M(int a)\r\n{}", "M(1)", 1, "a: 1", true)] + [InlineData("void M(int a\r\n) {}", "M(1)", 1, "a: 1", true)] + [InlineData("void M(\r\nint a\r\n) {}", "M(1)", 2, "a: 1", true)] + [InlineData("void M(int a) {\r\n\r\nConsole.WriteLine();}", "M(1)", 1, "a: 1")] + [InlineData("void M(in int a) {}", "M(1)", 1, "a: 1")] + [InlineData("void M(ref int a) {}", "int x = 1; M(ref x)", 1, "a: 1")] + [InlineData("void M(int a, int b) {}", "M(1, 2)", 1, "a: 1, b: 2")] + [InlineData("void M(int a, out int b) { b = 1; }", "M(1, out var _)", 1, "a: 1")] + [InlineData("void M(int a, int b = 0) {}", "M(1)", 1, "a: 1, b: 0")] + public async Task SlowUpdate_ReportsValueNotes_ForCSharpStaticMethodArguments(string methodCode, string methodCallCode, int expectedMethodLineNumber, string expectedNotes, bool expectedSkipped = false) { + var driver = await NewTestDriverAsync(@" using System; public static class Program { public static void Main() { " + methodCallCode + @"; } static " + methodCode + @" } "); - var methodStartLine = 4; // see above - - var result = await driver.SendSlowUpdateAsync(); - var steps = result.ExtensionResult?.Flow - .Select(s => new { s.Line, s.Notes, s.Skipped }) - .ToArray(); - - AssertIsSuccess(result); - Assert.Contains(new { Line = methodStartLine + expectedMethodLineNumber, Notes = expectedNotes, Skipped = expectedSkipped }, steps); - } + var methodStartLine = 4; // see above + + var result = await driver.SendSlowUpdateAsync(); + var steps = result.ExtensionResult?.Flow + .Select(s => new { s.Line, s.Notes, s.Skipped }) + .ToArray(); + + AssertIsSuccess(result); + Assert.Contains( + new { Line = methodStartLine + expectedMethodLineNumber, Notes = (string?)expectedNotes, Skipped = expectedSkipped }, + steps + ); + } - [Fact] - public async Task SlowUpdate_ReportsValueNotes_ForCSharpInstanceMethodArguments() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_ReportsValueNotes_ForCSharpInstanceMethodArguments() { + var driver = await NewTestDriverAsync(@" using System; public class Program { public static void Main() { new Program().M(1); } @@ -143,18 +147,18 @@ public void M(int a) {} } "); - var result = await driver.SendSlowUpdateAsync(); - var steps = result.ExtensionResult?.Flow - .Select(s => new { s.Line, s.Notes }) - .ToArray(); + var result = await driver.SendSlowUpdateAsync(); + var steps = result.ExtensionResult?.Flow + .Select(s => new { s.Line, s.Notes }) + .ToArray(); - AssertIsSuccess(result); - Assert.Contains(new { Line = 5, Notes = "a: 1" }, steps); - } + AssertIsSuccess(result); + Assert.Contains(new { Line = 5, Notes = (string?)"a: 1" }, steps); + } - [Fact] - public async Task SlowUpdate_ReportsValueNotes_ForCSharpConstructorArguments() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_ReportsValueNotes_ForCSharpConstructorArguments() { + var driver = await NewTestDriverAsync(@" using System; public class Program { Program(int a) {} @@ -162,138 +166,138 @@ public class Program { } "); - var result = await driver.SendSlowUpdateAsync(); - var steps = result.ExtensionResult?.Flow - .Select(s => new { s.Line, s.Notes }) - .ToArray(); + var result = await driver.SendSlowUpdateAsync(); + var steps = result.ExtensionResult?.Flow + .Select(s => new { s.Line, s.Notes }) + .ToArray(); - AssertIsSuccess(result); - Assert.Contains(new { Line = 4, Notes = "a: 1" }, steps); - } + AssertIsSuccess(result); + Assert.Contains(new { Line = 4, Notes = (string?)"a: 1" }, steps); + } - [Fact] - public async Task SlowUpdate_IncludesReturnValueInOutput() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_IncludesReturnValueInOutput() { + var driver = await NewTestDriverAsync(@" public static class Program { public static int Main() { return 3; } } "); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal("Return: 3", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal("Return: 3", result.ExtensionResult?.GetOutputAsString()); + } - [Fact] - public async Task SlowUpdate_IncludesExceptionInOutput() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_IncludesExceptionInOutput() { + var driver = await NewTestDriverAsync(@" public static class Program { public static int Main() { throw new System.Exception(""Test""); } } "); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result, allowRuntimeException: true); - Assert.Matches("^Exception: System.Exception: Test", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result, allowRuntimeException: true); + Assert.Matches("^Exception: System.Exception: Test", result.ExtensionResult?.GetOutputAsString()); + } - [Theory] - [InlineData("3.Inspect();", "Inspect: 3")] - [InlineData("(1, 2, 3).Inspect();", "Inspect: (1, 2, 3)")] - [InlineData("new[] { 1, 2, 3 }.Inspect();", "Inspect: { 1, 2, 3 }")] - [InlineData("3.Dump();", "Dump: 3")] - public async Task SlowUpdate_IncludesSimpleInspectAndDumpInOutput(string code, string expectedOutput) { - var driver = await NewTestDriverAsync(@" + [Theory] + [InlineData("3.Inspect();", "Inspect: 3")] + [InlineData("(1, 2, 3).Inspect();", "Inspect: (1, 2, 3)")] + [InlineData("new[] { 1, 2, 3 }.Inspect();", "Inspect: { 1, 2, 3 }")] + [InlineData("3.Dump();", "Dump: 3")] + public async Task SlowUpdate_IncludesSimpleInspectAndDumpInOutput(string code, string expectedOutput) { + var driver = await NewTestDriverAsync(@" public static class Program { public static void Main() { " + code + @" } } "); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal(expectedOutput, result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal(expectedOutput, result.ExtensionResult?.GetOutputAsString()); + } - [Theory] - [InlineData("Output.Inspect.Heap.Simple.cs2output")] - [InlineData("Output.Inspect.Heap.Struct.cs2output")] - [InlineData("Output.Inspect.Heap.Struct.Nested.cs2output")] - [InlineData("Output.Inspect.Heap.Int32.cs2output")] - [InlineData("Output.Inspect.Heap.Null.cs2output", true)] - public async Task SlowUpdate_IncludesInspectHeapInOutput(string resourceName, bool allowExceptions = false) { - var code = TestCode.FromResource("Execution." + resourceName); - var driver = await NewTestDriverAsync(code.Original); + [Theory] + [InlineData("Output.Inspect.Heap.Simple.cs2output")] + [InlineData("Output.Inspect.Heap.Struct.cs2output")] + [InlineData("Output.Inspect.Heap.Struct.Nested.cs2output")] + [InlineData("Output.Inspect.Heap.Int32.cs2output")] + [InlineData("Output.Inspect.Heap.Null.cs2output", true)] + public async Task SlowUpdate_IncludesInspectHeapInOutput(string resourceName, bool allowExceptions = false) { + var code = TestCode.FromResource("Execution." + resourceName); + var driver = await NewTestDriverAsync(code.Original); - var result = await SendSlowUpdateWithRetryOnMovedObjectsAsync(driver); + var result = await SendSlowUpdateWithRetryOnMovedObjectsAsync(driver); - AssertIsSuccess(result, allowRuntimeException: allowExceptions); - code.AssertIsExpected(result.ExtensionResult?.GetOutputAsString(), _output); - } + AssertIsSuccess(result, allowRuntimeException: allowExceptions); + await code.AssertIsExpectedAsync(result.ExtensionResult?.GetOutputAsString(), _output); + } - [Theory] - [InlineData("Output.Inspect.MemoryGraph.Int32.cs2output")] - [InlineData("Output.Inspect.MemoryGraph.String.cs2output")] - [InlineData("Output.Inspect.MemoryGraph.Arrays.cs2output")] - [InlineData("Output.Inspect.MemoryGraph.Variables.cs2output")] - [InlineData("Output.Inspect.MemoryGraph.DateTime.cs2output")] // https://github.com/ashmind/SharpLab/issues/379 - [InlineData("Output.Inspect.MemoryGraph.Null.cs2output")] - public async Task SlowUpdate_IncludesInspectMemoryGraphInOutput(string resourceName) { - var code = TestCode.FromResource("Execution." + resourceName); - var driver = await NewTestDriverAsync(code.Original); - - var result = await SendSlowUpdateWithRetryOnMovedObjectsAsync(driver); - - AssertIsSuccess(result); - code.AssertIsExpected(result.ExtensionResult?.GetOutputAsString(), _output); - } + [Theory] + [InlineData("Output.Inspect.MemoryGraph.Int32.cs2output")] + [InlineData("Output.Inspect.MemoryGraph.String.cs2output")] + [InlineData("Output.Inspect.MemoryGraph.Arrays.cs2output")] + [InlineData("Output.Inspect.MemoryGraph.Variables.cs2output")] + [InlineData("Output.Inspect.MemoryGraph.DateTime.cs2output")] // https://github.com/ashmind/SharpLab/issues/379 + [InlineData("Output.Inspect.MemoryGraph.Null.cs2output")] + public async Task SlowUpdate_IncludesInspectMemoryGraphInOutput(string resourceName) { + var code = TestCode.FromResource("Execution." + resourceName); + var driver = await NewTestDriverAsync(code.Original); + + var result = await SendSlowUpdateWithRetryOnMovedObjectsAsync(driver); + + AssertIsSuccess(result); + await code.AssertIsExpectedAsync(result.ExtensionResult?.GetOutputAsString(), _output); + } - [Theory] - [InlineData("Console.Write(\"abc\");", "abc")] - [InlineData("Console.WriteLine(\"abc\");", "abc{newline}")] - [InlineData("Console.Write('a');", "a")] - [InlineData("Console.Write(3);", "3")] - [InlineData("Console.Write(3.1);", "3.1")] - [InlineData("Console.Write(new object());", "System.Object")] - public async Task SlowUpdate_IncludesConsoleInOutput(string code, string expectedOutput) { - var driver = await NewTestDriverAsync(@" + [Theory] + [InlineData("Console.Write(\"abc\");", "abc")] + [InlineData("Console.WriteLine(\"abc\");", "abc{newline}")] + [InlineData("Console.Write('a');", "a")] + [InlineData("Console.Write(3);", "3")] + [InlineData("Console.Write(3.1);", "3.1")] + [InlineData("Console.Write(new object());", "System.Object")] + public async Task SlowUpdate_IncludesConsoleInOutput(string code, string expectedOutput) { + var driver = await NewTestDriverAsync(@" using System; public static class Program { public static void Main() { " + code + @" } } "); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal( - expectedOutput.Replace("{newline}", Environment.NewLine), - result.ExtensionResult?.GetOutputAsString() - ); - } + AssertIsSuccess(result); + Assert.Equal( + expectedOutput.Replace("{newline}", Environment.NewLine), + result.ExtensionResult?.GetOutputAsString() + ); + } - [Fact] - public async Task SlowUpdate_DoesNotIncludePreviousConsoleOutput_IfRunTwice() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_DoesNotIncludePreviousConsoleOutput_IfRunTwice() { + var driver = await NewTestDriverAsync(@" using System; public static class Program { public static void Main() { Console.Write('I'); } } "); - await driver.SendSlowUpdateAsync(); - var result = await driver.SendSlowUpdateAsync(); + await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal("I", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal("I", result.ExtensionResult?.GetOutputAsString()); + } - [Theory] - [InlineData("Console.Write(3.1);", "cs-CZ", "3.1")] - public async Task SlowUpdate_IncludesConsoleInOutput_UsingInvariantCulture(string code, string currentCultureName, string expectedOutput) { - var driver = await NewTestDriverAsync(@" + [Theory] + [InlineData("Console.Write(3.1);", "cs-CZ", "3.1")] + public async Task SlowUpdate_IncludesConsoleInOutput_UsingInvariantCulture(string code, string currentCultureName, string expectedOutput) { + var driver = await NewTestDriverAsync(@" using System; using System.Globalization; public static class Program { @@ -304,27 +308,27 @@ public static void Main() { } "); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal( - expectedOutput.Replace("{newline}", Environment.NewLine), - result.ExtensionResult?.GetOutputAsString() - ); - } + AssertIsSuccess(result); + Assert.Equal( + expectedOutput.Replace("{newline}", Environment.NewLine), + result.ExtensionResult?.GetOutputAsString() + ); + } - [Theory] - [InlineData("Api.Expressions.Simple.cs")] - public async Task SlowUpdate_AllowsExpectedApis(string resourceName) { - var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName)); - var result = await driver.SendSlowUpdateAsync(); + [Theory] + [InlineData("Api.Expressions.Simple.cs")] + public async Task SlowUpdate_AllowsExpectedApis(string resourceName) { + var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName)); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - } + AssertIsSuccess(result); + } - [Fact] - public async Task SlowUpdate_ExecutesVisualBasic() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_ExecutesVisualBasic() { + var driver = await NewTestDriverAsync(@" Imports System Public Module Program Public Sub Main() @@ -333,28 +337,28 @@ End Sub End Module ", LanguageNames.VisualBasic); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal("Test", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal("Test", result.ExtensionResult?.GetOutputAsString()); + } - [Fact] - public async Task SlowUpdate_ExecutesFSharp() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_ExecutesFSharp() { + var driver = await NewTestDriverAsync(@" open System printf ""Test"" ", "F#"); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal("Test", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal("Test", result.ExtensionResult?.GetOutputAsString()); + } - [Fact] - public async Task SlowUpdate_ExecutesFSharp_WithExplicitEntryPoint() { - var driver = await NewTestDriverAsync(@" + [Fact] + public async Task SlowUpdate_ExecutesFSharp_WithExplicitEntryPoint() { + var driver = await NewTestDriverAsync(@" open System [] @@ -363,30 +367,30 @@ open System 0 ", "F#"); - var result = await driver.SendSlowUpdateAsync(); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - Assert.Equal("Test\nReturn: 0", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result); + Assert.Equal("Test\nReturn: 0", result.ExtensionResult?.GetOutputAsString()); + } - [Theory] - [InlineData("Regression.CertainLoop.cs")] - [InlineData("Regression.FSharpNestedLambda.fs", LanguageNames.FSharp)] - [InlineData("Regression.NestedAnonymousObject.cs")] - [InlineData("Regression.ReturnRef.cs")] - public async Task SlowUpdate_DoesNotFail(string resourceName, string languageName = LanguageNames.CSharp) { - var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), languageName); - var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - } + [Theory] + [InlineData("Regression.CertainLoop.cs")] + [InlineData("Regression.FSharpNestedLambda.fs", LanguageNames.FSharp)] + [InlineData("Regression.NestedAnonymousObject.cs")] + [InlineData("Regression.ReturnRef.cs")] + public async Task SlowUpdate_DoesNotFail(string resourceName, string languageName = LanguageNames.CSharp) { + var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), languageName); + var result = await driver.SendSlowUpdateAsync(); + AssertIsSuccess(result); + } - [Theory] // https://github.com/ashmind/SharpLab/issues/388 - [InlineData("void M(Span s) {}", "M(new Span())")] - [InlineData("void M(ref Span s) {}", "var s = new Span(); M(ref s)")] - [InlineData("void M(ReadOnlySpan s) {}", "M(new ReadOnlySpan())")] - [InlineData("void M(ref ReadOnlySpan s) {}", "var s = new ReadOnlySpan(); M(ref s)")] - public async Task SlowUpdate_DoesNotFail_OnSpanArguments(string methodCode, string methodCallCode) { - var driver = await NewTestDriverAsync(@" + [Theory] // https://github.com/ashmind/SharpLab/issues/388 + [InlineData("void M(Span s) {}", "M(new Span())")] + [InlineData("void M(ref Span s) {}", "var s = new Span(); M(ref s)")] + [InlineData("void M(ReadOnlySpan s) {}", "M(new ReadOnlySpan())")] + [InlineData("void M(ref ReadOnlySpan s) {}", "var s = new ReadOnlySpan(); M(ref s)")] + public async Task SlowUpdate_DoesNotFail_OnSpanArguments(string methodCode, string methodCallCode) { + var driver = await NewTestDriverAsync(@" using System; public static class Program { public static void Main() { @@ -395,17 +399,17 @@ public static void Main() { static " + methodCode + @" } "); - var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - } + var result = await driver.SendSlowUpdateAsync(); + AssertIsSuccess(result); + } - [Theory] - [InlineData("digits.Sort((a, b) => a.CompareTo(b));")] // https://github.com/ashmind/SharpLab/issues/411 - [InlineData("digits.Sort(delegate(int a, int b) { return a.CompareTo(b); });")] - [InlineData("int Compare(int a, int b) => a.CompareTo(b); digits.Sort(Compare);")] - [InlineData("digits.Find(a => a > 0);")] - public async Task SlowUpdate_DoesNotFail_OnNestedMethodCall_ForCSharp(string callWithAnonymousMethodCode) { - var driver = await NewTestDriverAsync(@" + [Theory] + [InlineData("digits.Sort((a, b) => a.CompareTo(b));")] // https://github.com/ashmind/SharpLab/issues/411 + [InlineData("digits.Sort(delegate(int a, int b) { return a.CompareTo(b); });")] + [InlineData("int Compare(int a, int b) => a.CompareTo(b); digits.Sort(Compare);")] + [InlineData("digits.Find(a => a > 0);")] + public async Task SlowUpdate_DoesNotFail_OnNestedMethodCall_ForCSharp(string callWithAnonymousMethodCode) { + var driver = await NewTestDriverAsync(@" using System.Collections.Generic; public static class Program { public static void Main(string[] args) { @@ -414,13 +418,13 @@ public static void Main(string[] args) { } } "); - var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - } + var result = await driver.SendSlowUpdateAsync(); + AssertIsSuccess(result); + } - [Fact] // https://github.com/ashmind/SharpLab/issues/411 - public async Task SlowUpdate_DoesNotFail_OnLambdaParameterList_ForVisualBasic() { - var driver = await NewTestDriverAsync(@" + [Fact] // https://github.com/ashmind/SharpLab/issues/411 + public async Task SlowUpdate_DoesNotFail_OnLambdaParameterList_ForVisualBasic() { + var driver = await NewTestDriverAsync(@" Imports System.Collections.Generic Public Module Program Public Sub Main(ByVal args() As String) @@ -429,107 +433,104 @@ Dim list as New List(of Integer) End Sub End Module ", LanguageNames.VisualBasic); - var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result); - } + var result = await driver.SendSlowUpdateAsync(); + AssertIsSuccess(result); + } - [Theory] - [InlineData("Regression.Disposable.cs", Skip = "Fails GitHub Actions, see https://github.com/ashmind/SharpLab/issues/591")] - public async Task SlowUpdate_DoesNotFail_OnAnyGuard(string resourceName) { - var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), LanguageNames.CSharp); - var result = await driver.SendSlowUpdateAsync(); + [Theory] + [InlineData("Regression.Disposable.cs", Skip = "Fails GitHub Actions, see https://github.com/ashmind/SharpLab/issues/591")] + public async Task SlowUpdate_DoesNotFail_OnAnyGuard(string resourceName) { + var driver = await NewTestDriverAsync(LoadCodeFromResource(resourceName), LanguageNames.CSharp); + var result = await driver.SendSlowUpdateAsync(); - AssertIsSuccess(result, allowRuntimeException: true); - Assert.DoesNotMatch("GuardException", result.ExtensionResult?.GetOutputAsString()); - } + AssertIsSuccess(result, allowRuntimeException: true); + Assert.DoesNotMatch("GuardException", result.ExtensionResult?.GetOutputAsString()); + } - // Currently Inspect.Heap/MemoryGraph does not promise to always work as expected if GCs happen - // during its operation. So for now we retry in the tests. - private async Task> SendSlowUpdateWithRetryOnMovedObjectsAsync(MirrorSharpTestDriver driver) { - var result = await driver.SendSlowUpdateAsync(); - var tryCount = 1; - while ((result.ExtensionResult?.GetOutputAsString().Contains("Failed to find object type for address") ?? false) && tryCount < 10) { - _output.WriteLine($"Failed to find object type for address, retrying ({tryCount}) ..."); - result = await driver.SendSlowUpdateAsync(); - tryCount += 1; - } - return result!; + // Currently Inspect.Heap/MemoryGraph does not promise to always work as expected if GCs happen + // during its operation. So for now we retry in the tests. + private async Task> SendSlowUpdateWithRetryOnMovedObjectsAsync(MirrorSharpTestDriver driver) { + var result = await driver.SendSlowUpdateAsync(); + var tryCount = 1; + while ((result.ExtensionResult?.GetOutputAsString().Contains("Failed to find object type for address") ?? false) && tryCount < 10) { + _output.WriteLine($"Failed to find object type for address, retrying ({tryCount}) ..."); + result = await driver.SendSlowUpdateAsync(); + tryCount += 1; } + return result!; + } - private static void AssertIsSuccess(SlowUpdateResult result, bool allowRuntimeException = false) { - var errors = result.JoinErrors(); - Assert.True(string.IsNullOrEmpty(errors), errors); - var output = result.ExtensionResult?.GetOutputAsString(); - Assert.DoesNotMatch("InvalidProgramException", output); + private static void AssertIsSuccess(SlowUpdateResult result, bool allowRuntimeException = false) { + var errors = result.JoinErrors(); + Assert.True(string.IsNullOrEmpty(errors), errors); + var output = result.ExtensionResult?.GetOutputAsString(); + Assert.DoesNotMatch("InvalidProgramException", output); - if (allowRuntimeException) - return; - Assert.DoesNotMatch("Exception:", output); - } + if (allowRuntimeException) + return; + Assert.DoesNotMatch("Exception:", output); + } - private static string LoadCodeFromResource(string resourceName) { - return EmbeddedResource.ReadAllText(typeof(ExecutionTests), "TestCode.Execution." + resourceName); - } + private static string LoadCodeFromResource(string resourceName) { + return EmbeddedResource.ReadAllText(typeof(ExecutionTests), "TestCode.Execution." + resourceName); + } - private static async Task NewTestDriverAsync( - string code, - string languageName = LanguageNames.CSharp, - string optimize = Optimize.Debug - ) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(languageName, TargetNames.Run, optimize); - return driver; - } + private static async Task NewTestDriverAsync( + string code, + string languageName = LanguageNames.CSharp, + string optimize = Optimize.Debug + ) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(languageName, TargetNames.Run, optimize); + return driver; + } - private class ExecutionResultData { - [JsonIgnore] - public IList Flow { get; } = new List(); - [JsonProperty("flow")] - private IList FlowRaw { get; } = new List(); - [JsonProperty] - private IList Output { get; } = new List(); - - public string GetOutputAsString() { - return string.Join("\n", Output.Select(token => { - if (token is JObject @object) - return ConvertOutputObjectToString(@object); - return token.Value(); - })); - } + private class ExecutionResultData { + [JsonIgnore] + public IList Flow { get; } = new List(); + [JsonProperty("flow")] + private IList FlowRaw { get; } = new List(); + [JsonProperty] + private IList Output { get; } = new List(); + + public string GetOutputAsString() { + return string.Join("\n", Output.Select(token => { + if (token is JObject @object) + return ConvertOutputObjectToString(@object); + return token.Value(); + })); + } - private string ConvertOutputObjectToString(JObject @object) { - if (@object.Value("type") == "inspection:simple") - return @object.Value("title") + ": " + @object.Value("value"); - return @object.ToString(); - } + private string ConvertOutputObjectToString(JObject @object) { + if (@object.Value("type") == "inspection:simple") + return @object.Value("title") + ": " + @object.Value("value"); + return @object.ToString(); + } - [OnDeserialized] - private void OnDeserialized(StreamingContext context) { - foreach (var token in FlowRaw) { - Flow.Add(ParseStepData(token)); - } + [OnDeserialized] + private void OnDeserialized(StreamingContext context) { + foreach (var token in FlowRaw) { + Flow.Add(ParseStepData(token)); } + } - private FlowStepData ParseStepData(JToken token) { - if (token is JValue value) - return new FlowStepData { Line = value.Value() }; + private FlowStepData ParseStepData(JToken token) { + if (token is JValue value) + return new FlowStepData { Line = value.Value() }; - return new FlowStepData { - Line = token.Value("line"), - Exception = token.Value("exception"), - Notes = token.Value("notes"), - Skipped = token.Value("skipped") ?? false, - }; - } + return new FlowStepData { + Line = token.Value("line"), + Exception = token.Value("exception"), + Notes = token.Value("notes"), + Skipped = token.Value("skipped") ?? false, + }; } + } - private class FlowStepData { -#pragma warning disable CS8618 // Non-nullable field is uninitialized. - public int Line { get; set; } - public string Exception { get; set; } - public string Notes { get; set; } - public bool Skipped { get; set; } -#pragma warning restore CS8618 // Non-nullable field is uninitialized. - } + private class FlowStepData { + public int Line { get; set; } + public string? Exception { get; set; } + public string? Notes { get; set; } + public bool Skipped { get; set; } } } \ No newline at end of file diff --git a/source/NetFramework/Tests/Internal/ModuleInitializerAttribute.cs b/source/NetFramework/Tests/Internal/ModuleInitializerAttribute.cs new file mode 100644 index 000000000..39e87e63a --- /dev/null +++ b/source/NetFramework/Tests/Internal/ModuleInitializerAttribute.cs @@ -0,0 +1,7 @@ +namespace System.Runtime.CompilerServices { + [AttributeUsage(AttributeTargets.Method, Inherited = false)] + public class ModuleInitializerAttribute : Attribute { + public ModuleInitializerAttribute() { + } + } +} diff --git a/source/NetFramework/Tests/Internal/TestCode.cs b/source/NetFramework/Tests/Internal/TestCode.cs index beac20d20..a0d5abced 100644 --- a/source/NetFramework/Tests/Internal/TestCode.cs +++ b/source/NetFramework/Tests/Internal/TestCode.cs @@ -4,116 +4,144 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Pedantic.IO; using SharpLab.Server.Common; using Xunit; using Xunit.Abstractions; -namespace SharpLab.Tests.Internal { - public class TestCode { - private static readonly IReadOnlyDictionary LanguageAndTargetMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { - { "cs", LanguageNames.CSharp }, - { "vb", LanguageNames.VisualBasic }, - { "fs", LanguageNames.FSharp }, - { "il", TargetNames.IL }, - { "asm", TargetNames.JitAsm }, - { "ast", TargetNames.Ast }, - { "output", TargetNames.Run }, - }; - - public string Original { get; } - public string SourceLanguageName { get; } - public string TargetName { get; } - - private readonly string _expected; - - public TestCode(string original, string expected, string sourceLanguageName, string targetName) { - Original = original; - SourceLanguageName = sourceLanguageName; - TargetName = targetName; - _expected = expected; - } +namespace SharpLab.Tests.Internal; + +public class TestCode { + private static readonly IReadOnlyDictionary LanguageAndTargetMap = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { "cs", LanguageNames.CSharp }, + { "vb", LanguageNames.VisualBasic }, + { "fs", LanguageNames.FSharp }, + { "il", TargetNames.IL }, + { "asm", TargetNames.JitAsm }, + { "ast", TargetNames.Ast }, + { "output", TargetNames.Run }, + }; + + private static readonly IReadOnlyDictionary CommentMarkers = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { LanguageNames.CSharp, ("/*", "*/") }, + { LanguageNames.VisualBasic, ("/*", "*/") }, // TODO: Sort out + { LanguageNames.FSharp, ("(*", "*)") }, + { LanguageNames.IL, ("/*", "*/") }, + }; + + private static bool ShouldUpdateOnAssert => Environment.GetEnvironmentVariable("SHARPLAB_TEST_UPDATE_SNAPSHOTS") == "true"; + + public string Original { get; } + public string SourceLanguageName { get; } + public string TargetName { get; } + + private readonly string _expected; + private readonly string? _snapshotFilePath; + + public TestCode(string original, string expected, string sourceLanguageName, string targetName, string? snapshotFilePath = null) { + Original = original; + SourceLanguageName = sourceLanguageName; + TargetName = targetName; + _expected = expected; + _snapshotFilePath = snapshotFilePath; + } - public static TestCode FromFile(string relativePath, [CallerFilePath] string callerFilePath = "") { - var testBasePath = Path.GetDirectoryName(callerFilePath)!; - var fullPath = Path.Combine(AppContext.BaseDirectory, testBasePath, "TestCode", relativePath); + public static TestCode FromFile(string relativePath, [CallerFilePath] string callerFilePath = "") { + var testBasePath = Path.GetDirectoryName(callerFilePath)!; + var fullPath = Path.Combine(AppContext.BaseDirectory, testBasePath, "TestCode", relativePath); - var content = File.ReadAllText(fullPath); - var extension = Path.GetExtension(relativePath); + var content = File.ReadAllText(fullPath); + var extension = Path.GetExtension(relativePath); - return FromContent(content, extension); - } + return FromContent(content, extension, fullPath); + } - public static TestCode FromResource(string name) { - var content = EmbeddedResource.ReadAllText(typeof(ExecutionTests), "TestCode." + name); - var extension = Path.GetExtension(name); + public static TestCode FromResource(string name) { + var content = EmbeddedResource.ReadAllText(typeof(ExecutionTests), "TestCode." + name); + var extension = Path.GetExtension(name); - return FromContent(content, extension); - } + return FromContent(content, extension); + } - private static TestCode FromContent(string content, string extension) { - if (extension.Contains("2")) - return FromContentFormatV1(content, extension); + private static TestCode FromContent(string content, string extension, string? sourceFilePath = null) { + if (extension.Contains("2")) + return FromContentFormatV1(content, extension); - var split = Regex.Matches(content, @"[/(]\* (?\S+)").Cast().Last(); - var from = LanguageAndTargetMap[extension.TrimStart('.')]; - var to = LanguageAndTargetMap[split.Groups["to"].Value]; + var split = Regex.Matches(content, @"^[/(]\* (?\S+)", RegexOptions.Multiline).Cast().Last(); + var from = LanguageAndTargetMap[extension.TrimStart('.')]; + var to = LanguageAndTargetMap[split.Groups["to"].Value]; - var code = content.Substring(0, split.Index).Trim(); - var expected = Regex.Replace( - content.Substring(split.Index + split.Value.Length), - @"^\s+|\s*\*[/)]\s*$", "" - ); + var code = content.Substring(0, split.Index).Trim(); + var expected = Regex.Replace( + content.Substring(split.Index + split.Value.Length), + @"^\s+|\s*\*[/)]\s*$", "" + ); - return new TestCode(code, expected, from, to); - } + return new TestCode(code, expected, from, to, sourceFilePath); + } - private static TestCode FromContentFormatV1(string content, string extension) { - var parts = content.Split(new[] { "#=>" }, StringSplitOptions.None); - var code = parts[0].Trim(); - var expected = parts[1].Trim(); - // ReSharper disable once PossibleNullReferenceException - var fromTo = extension.TrimStart('.').Split('2').Select(x => LanguageAndTargetMap[x]).ToList(); + private static TestCode FromContentFormatV1(string content, string extension) { + var parts = content.Split(new[] { "#=>" }, StringSplitOptions.None); + var code = parts[0].Trim(); + var expected = parts[1].Trim(); + // ReSharper disable once PossibleNullReferenceException + var fromTo = extension.TrimStart('.').Split('2').Select(x => LanguageAndTargetMap[x]).ToList(); - return new TestCode(code, expected, fromTo[0], fromTo[1]); - } + return new TestCode(code, expected, fromTo[0], fromTo[1]); + } - public void AssertIsExpected(string? result, ITestOutputHelper output) { - var cleanResult = RemoveNonDeterminism(result?.Trim()); - output.WriteLine(cleanResult ?? ""); - Assert.Equal(NormalizeNewLines(_expected), NormalizeNewLines(cleanResult)); - } + public async Task AssertIsExpectedAsync(string? result, ITestOutputHelper output) { + var cleanResult = RemoveNonDeterminism(result?.Trim()); + output.WriteLine(cleanResult ?? ""); - private string? RemoveNonDeterminism(string? result) { - if (result == null) - return null; + if (_snapshotFilePath is { } path && cleanResult is { } actual && ShouldUpdateOnAssert) { + await UpdateFileAsync(path, actual); + return; + } - result = Regex.Replace(result, @"0x[\dA-Fa-f]{7,16}(?=$|[^\dA-Fa-f])", "0x"); + Assert.Equal(NormalizeNewLines(_expected), NormalizeNewLines(cleanResult)); + } - if (TargetName == TargetNames.JitAsm) - result = Regex.Replace(result, @"CLR [\d\.]+", "CLR "); + private string? RemoveNonDeterminism(string? result) { + if (result == null) + return null; + + result = Regex.Replace(result, @"0x[\dA-Fa-f]{7,16}(?=$|[^\dA-Fa-f])", "0x"); + + if (TargetName == TargetNames.JitAsm) + result = Regex.Replace(result, @"CLR [\d\.]+", "CLR "); + + if (TargetName == TargetNames.Run) { + // we need to ignore type handle in memory inspection output + var pattern = @"(?""inspection:memory"",.+""data"":\s*\[\s*)" + + @"(?
(?:\d+,\s*){" + IntPtr.Size + "})" + + @"(?(?:\d+,\s*){" + IntPtr.Size + "})"; + result = Regex.Replace(result, pattern, m => { + var ignored = Regex.Replace(m.Groups["typeHandle"].Value, @"\d+", ""); + return m.Groups["prefix"].Value + + m.Groups["header"].Value + + ignored; + }, RegexOptions.Singleline); + + // ignoring paths in exception stack traces. can't use as paths are simply not present in Release mode + result = Regex.Replace(result, @" in (?:/[A-Za-z]{2,}/|[A-Za-z]:[/\\])[^\r\n]+", ""); + } - if (TargetName == TargetNames.Run) { - // we need to ignore type handle in memory inspection output - var pattern = @"(?""inspection:memory"",.+""data"":\s*\[\s*)" - + @"(?
(?:\d+,\s*){" + IntPtr.Size + "})" - + @"(?(?:\d+,\s*){" + IntPtr.Size + "})"; - result = Regex.Replace(result, pattern, m => { - var ignored = Regex.Replace(m.Groups["typeHandle"].Value, @"\d+", ""); - return m.Groups["prefix"].Value - + m.Groups["header"].Value - + ignored; - }, RegexOptions.Singleline); + return result; + } - // ignoring paths in exception stack traces. can't use as paths are simply not present in Release mode - result = Regex.Replace(result, @" in (?:/[A-Za-z]{2,}/|[A-Za-z]:[/\\])[^\r\n]+", ""); - } + private string? NormalizeNewLines(string? value) { + return value?.Replace("\r\n", "\n"); + } - return result; - } + private async Task UpdateFileAsync(string path, string actual) { + var (commentStart, commentEnd) = CommentMarkers[SourceLanguageName]; + var targetExtension = LanguageAndTargetMap.First(p => p.Value == TargetName).Key; - private string? NormalizeNewLines(string? value) { - return value?.Replace("\r\n", "\n"); + var updatedContent = $"{Original}\r\n\r\n{commentStart} {targetExtension}\r\n\r\n{actual}\r\n\r\n{commentEnd}"; + using (var writer = new StreamWriter(path)) { + await writer.WriteAsync(updatedContent); } } -} +} \ No newline at end of file diff --git a/source/NetFramework/Tests/Internal/TestEnvironment.cs b/source/NetFramework/Tests/Internal/TestEnvironment.cs index fe67e73c0..8a0687dcd 100644 --- a/source/NetFramework/Tests/Internal/TestEnvironment.cs +++ b/source/NetFramework/Tests/Internal/TestEnvironment.cs @@ -5,25 +5,29 @@ using MirrorSharp.Advanced.EarlyAccess; using MirrorSharp.Testing; using SharpLab.Server; +using SharpLab.Server.Common; -namespace SharpLab.Tests.Internal { - public static class TestEnvironment { - public static IContainer Container { get; } = ((Func)(() => { - var builder = new ContainerBuilder(); - StartupHelper.ConfigureContainer(builder); - return builder.Build(); - }))(); +namespace SharpLab.Tests.Internal; - public static MirrorSharpOptions MirrorSharpOptions { get; } = StartupHelper.CreateMirrorSharpOptions(Container); +public static class TestEnvironment { + public static IContainer Container { get; } = ((Func)(() => { + Environment.SetEnvironmentVariable("SHARPLAB_WEBAPP_NAME", "sl-test"); + DotEnv.Load(); - public static MirrorSharpServices MirrorSharpServices { get; } = new MirrorSharpServices { - SetOptionsFromClient = Container.ResolveOptional(), - SlowUpdate = Container.ResolveOptional(), - RoslynSourceTextGuard = Container.ResolveOptional(), - RoslynCompilationGuard = Container.ResolveOptional(), - ExceptionLogger = Container.ResolveOptional() - }; + var builder = new ContainerBuilder(); + StartupHelper.ConfigureContainer(builder); + return builder.Build(); + }))(); - public static MirrorSharpTestDriver NewDriver() => MirrorSharpTestDriver.New(MirrorSharpOptions, MirrorSharpServices); - } + public static MirrorSharpOptions MirrorSharpOptions { get; } = StartupHelper.CreateMirrorSharpOptions(Container); + + public static MirrorSharpServices MirrorSharpServices { get; } = new MirrorSharpServices { + SetOptionsFromClient = Container.ResolveOptional(), + SlowUpdate = Container.ResolveOptional(), + RoslynSourceTextGuard = Container.ResolveOptional(), + RoslynCompilationGuard = Container.ResolveOptional(), + ExceptionLogger = Container.ResolveOptional() + }; + + public static MirrorSharpTestDriver NewDriver() => MirrorSharpTestDriver.New(MirrorSharpOptions, MirrorSharpServices); } diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Int32.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Int32.cs2output index 5ddff3eca..cd77b3fd9 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Int32.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Int32.cs2output @@ -16,20 +16,24 @@ public static class Program { { "name": "header", "offset": 0, - "length": 4 + "length": 8 }, { "name": "type handle", - "offset": 4, - "length": 4 + "offset": 8, + "length": 8 }, { "name": "m_value", - "offset": 8, + "offset": 16, "length": 4 } ], "data": [ + 0, + 0, + 0, + 0, 0, 0, 0, @@ -38,9 +42,17 @@ public static class Program { , , , + , + , + , + , 5, 0, 0, + 0, + 0, + 0, + 0, 0 ] } \ No newline at end of file diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Simple.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Simple.cs2output index 1efa0e806..3d2a3511a 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Simple.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Simple.cs2output @@ -21,21 +21,21 @@ public static class Program { { "name": "header", "offset": 0, - "length": 4 + "length": 8 }, { "name": "type handle", - "offset": 4, - "length": 4 + "offset": 8, + "length": 8 }, { "name": "a", - "offset": 8, + "offset": 16, "length": 4 }, { "name": "b", - "offset": 12, + "offset": 20, "length": 1 } ], @@ -44,6 +44,14 @@ public static class Program { 0, 0, 0, + 0, + 0, + 0, + 0, + , + , + , + , , , , diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.Nested.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.Nested.cs2output index baf6729a8..3e51e243f 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.Nested.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.Nested.cs2output @@ -27,36 +27,36 @@ public static class Program { { "name": "header", "offset": 0, - "length": 4 + "length": 8 }, { "name": "type handle", - "offset": 4, - "length": 4 + "offset": 8, + "length": 8 }, { "name": "a", - "offset": 8, + "offset": 16, "length": 4 }, { "name": "b", - "offset": 12, + "offset": 20, "length": 1 }, { "name": "n", - "offset": 16, + "offset": 24, "length": 5, "nested": [ { "name": "an", - "offset": 16, + "offset": 24, "length": 4 }, { "name": "bn", - "offset": 20, + "offset": 28, "length": 1 } ] @@ -67,6 +67,14 @@ public static class Program { 0, 0, 0, + 0, + 0, + 0, + 0, + , + , + , + , , , , diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.cs2output index 0e89e6d14..def27944e 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.Heap.Struct.cs2output @@ -21,21 +21,21 @@ public static class Program { { "name": "header", "offset": 0, - "length": 4 + "length": 8 }, { "name": "type handle", - "offset": 4, - "length": 4 + "offset": 8, + "length": 8 }, { "name": "a", - "offset": 8, + "offset": 16, "length": 4 }, { "name": "b", - "offset": 12, + "offset": 20, "length": 1 } ], @@ -44,6 +44,14 @@ public static class Program { 0, 0, 0, + 0, + 0, + 0, + 0, + , + , + , + , , , , diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Arrays.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Arrays.cs2output index 044edf448..614099b13 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Arrays.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Arrays.cs2output @@ -16,7 +16,7 @@ public static class Program { { "id": 1, "offset": 0, - "size": 4, + "size": 8, "title": null, "value": "Int32[] ref" } @@ -58,7 +58,7 @@ public static class Program { { "id": 6, "offset": 0, - "size": 4, + "size": 8, "title": null, "value": "String[] ref" } diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Null.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Null.cs2output index f61d64008..32dd29a84 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Null.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Null.cs2output @@ -14,7 +14,7 @@ public static class Program { { "id": 1, "offset": 0, - "size": 4, + "size": 8, "title": null, "value": "null" } diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.String.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.String.cs2output index 3ac293c27..6ccc592ac 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.String.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.String.cs2output @@ -15,7 +15,7 @@ public static class Program { { "id": 1, "offset": 0, - "size": 4, + "size": 8, "title": null, "value": "String ref" } diff --git a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Variables.cs2output b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Variables.cs2output index 9cf986be8..db8977588 100644 --- a/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Variables.cs2output +++ b/source/NetFramework/Tests/TestCode/Execution/Output/Inspect.MemoryGraph.Variables.cs2output @@ -18,7 +18,7 @@ public static class Program { "stack": [ { "id": 1, - "offset": 8, + "offset": 12, "size": 4, "title": "a", "value": "1" @@ -26,7 +26,7 @@ public static class Program { { "id": 2, "offset": 0, - "size": 4, + "size": 8, "title": "c", "value": "String ref" } @@ -44,7 +44,7 @@ public static class Program { "to": 3 } ] -} +} { "type": "inspection:memory-graph", "stack": [ diff --git a/source/NetFramework/Tests/Tests.csproj b/source/NetFramework/Tests/Tests.csproj index 8296bc990..d1a468fa8 100644 --- a/source/NetFramework/Tests/Tests.csproj +++ b/source/NetFramework/Tests/Tests.csproj @@ -1,8 +1,10 @@ - + net48 SharpLab.Tests SharpLab.Tests + x64 + x64 @@ -32,7 +34,7 @@ - + @@ -40,6 +42,12 @@ + + + PreserveNewest + + + diff --git a/source/Runtime/Internal/ContainerFlow.cs b/source/Runtime/Internal/ContainerFlow.cs index 339462573..d5d34c1af 100644 --- a/source/Runtime/Internal/ContainerFlow.cs +++ b/source/Runtime/Internal/ContainerFlow.cs @@ -1,39 +1,15 @@ using System; namespace SharpLab.Runtime.Internal { + [Obsolete("Only preserved for binary compatbility with older branches.", error: true)] public static class ContainerFlow { - public const int UnknownLineNumber = -1; - - public static void ReportLineStart(int lineNumber) { - RuntimeServices.FlowWriter.WriteLineVisit(lineNumber); - } - - public static void ReportRefValue(ref T value, string? name, int lineNumber) { - ReportValue(value, name, lineNumber); - } - - public static void ReportValue(T value, string? name, int lineNumber) { - RuntimeServices.FlowWriter.WriteValue(value, name, lineNumber); - } - - public static void ReportRefSpanValue(ref Span value, string? name, int lineNumber) { - ReportReadOnlySpanValue((ReadOnlySpan)value, name, lineNumber); - } - - public static void ReportSpanValue(Span value, string? name, int lineNumber) { - ReportReadOnlySpanValue((ReadOnlySpan)value, name, lineNumber); - } - - public static void ReportRefReadOnlySpanValue(ref ReadOnlySpan value, string? name, int lineNumber) { - ReportReadOnlySpanValue(value, name, lineNumber); - } - - public static void ReportReadOnlySpanValue(ReadOnlySpan value, string? name, int lineNumber) { - RuntimeServices.FlowWriter.WriteSpanValue(value, name, lineNumber); - } - - public static void ReportException(object exception) { - RuntimeServices.FlowWriter.WriteException(exception); - } + public static void ReportLineStart(int lineNumber) => Flow.ReportLineStart(lineNumber); + public static void ReportRefValue(ref T value, string? name, int lineNumber) => Flow.ReportRefValue(ref value, name, lineNumber); + public static void ReportValue(T value, string? name, int lineNumber) => Flow.ReportValue(value, name, lineNumber); + public static void ReportRefSpanValue(ref Span value, string? name, int lineNumber) => Flow.ReportRefSpanValue(ref value, name, lineNumber); + public static void ReportSpanValue(Span value, string? name, int lineNumber) => Flow.ReportSpanValue(value, name, lineNumber); + public static void ReportRefReadOnlySpanValue(ref ReadOnlySpan value, string? name, int lineNumber) => Flow.ReportRefReadOnlySpanValue(ref value, name, lineNumber); + public static void ReportReadOnlySpanValue(ReadOnlySpan value, string? name, int lineNumber) => Flow.ReportReadOnlySpanValue(value, name, lineNumber); + public static void ReportException(object exception) => Flow.ReportException(exception); } } diff --git a/source/Runtime/Internal/Flow.cs b/source/Runtime/Internal/Flow.cs new file mode 100644 index 000000000..c4f9a6e36 --- /dev/null +++ b/source/Runtime/Internal/Flow.cs @@ -0,0 +1,58 @@ +using System; + +namespace SharpLab.Runtime.Internal { + public static class Flow { + public const int UnknownLineNumber = -1; + + public static void ReportMethodArea(int startLineNumber, int endLineNumber) { + RuntimeServices.FlowWriter.WriteArea(FlowAreaKind.Method, startLineNumber, endLineNumber); + } + + public static void ReportLoopArea(int startLineNumber, int endLineNumber) { + RuntimeServices.FlowWriter.WriteArea(FlowAreaKind.Loop, startLineNumber, endLineNumber); + } + + public static void ReportLineStart(int lineNumber) { + RuntimeServices.FlowWriter.WriteLineVisit(lineNumber); + } + public static void ReportJump() { + RuntimeServices.FlowWriter.WriteTag(FlowRecordTag.Jump); + } + + public static void ReportLoopStart() { + RuntimeServices.FlowWriter.WriteTag(FlowRecordTag.LoopStart); + } + + public static void ReportLoopEnd() { + RuntimeServices.FlowWriter.WriteTag(FlowRecordTag.LoopEnd); + } + + public static void ReportRefValue(ref T value, string? name, int lineNumber) { + ReportValue(value, name, lineNumber); + } + + public static void ReportValue(T value, string? name, int lineNumber) { + RuntimeServices.FlowWriter.WriteValue(value, name, lineNumber); + } + + public static void ReportRefSpanValue(ref Span value, string? name, int lineNumber) { + ReportReadOnlySpanValue((ReadOnlySpan)value, name, lineNumber); + } + + public static void ReportSpanValue(Span value, string? name, int lineNumber) { + ReportReadOnlySpanValue((ReadOnlySpan)value, name, lineNumber); + } + + public static void ReportRefReadOnlySpanValue(ref ReadOnlySpan value, string? name, int lineNumber) { + ReportReadOnlySpanValue(value, name, lineNumber); + } + + public static void ReportReadOnlySpanValue(ReadOnlySpan value, string? name, int lineNumber) { + RuntimeServices.FlowWriter.WriteSpanValue(value, name, lineNumber); + } + + public static void ReportException(object exception) { + RuntimeServices.FlowWriter.WriteException(exception); + } + } +} diff --git a/source/Runtime/Internal/FlowAreaKind.cs b/source/Runtime/Internal/FlowAreaKind.cs new file mode 100644 index 000000000..65034e460 --- /dev/null +++ b/source/Runtime/Internal/FlowAreaKind.cs @@ -0,0 +1,6 @@ +namespace SharpLab.Runtime.Internal { + public enum FlowAreaKind { + Loop, + Method + } +} diff --git a/source/Runtime/Internal/FlowRecordTag.cs b/source/Runtime/Internal/FlowRecordTag.cs new file mode 100644 index 000000000..fd0eb4c4a --- /dev/null +++ b/source/Runtime/Internal/FlowRecordTag.cs @@ -0,0 +1,7 @@ +namespace SharpLab.Runtime.Internal { + internal enum FlowRecordTag { + LoopStart, + LoopEnd, + Jump + } +} diff --git a/source/Runtime/Internal/IFlowWriter.cs b/source/Runtime/Internal/IFlowWriter.cs index 13e647cbd..73c4fdc0b 100644 --- a/source/Runtime/Internal/IFlowWriter.cs +++ b/source/Runtime/Internal/IFlowWriter.cs @@ -2,9 +2,11 @@ namespace SharpLab.Runtime.Internal { internal interface IFlowWriter { + void WriteArea(FlowAreaKind kind, int startLineNumber, int endLineNumber); void WriteLineVisit(int lineNumber); void WriteValue(T value, string? name, int lineNumber); void WriteSpanValue(ReadOnlySpan value, string? name, int lineNumber); + void WriteTag(FlowRecordTag tag); void WriteException(object exception); } } diff --git a/source/Runtime/NoILRewritingAttribute.cs b/source/Runtime/NoILRewritingAttribute.cs new file mode 100644 index 000000000..f973508e1 --- /dev/null +++ b/source/Runtime/NoILRewritingAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace SharpLab.Runtime { + [AttributeUsage(AttributeTargets.Assembly)] + public sealed class NoILRewritingAttribute : Attribute { + } +} diff --git a/source/Runtime/Runtime.csproj b/source/Runtime/Runtime.csproj index 74e8a2593..0be6a26b6 100644 --- a/source/Runtime/Runtime.csproj +++ b/source/Runtime/Runtime.csproj @@ -8,7 +8,7 @@ - + diff --git a/source/Server/Caching/CachingMetrics.cs b/source/Server/Caching/CachingMetrics.cs deleted file mode 100644 index 7089af2fa..000000000 --- a/source/Server/Caching/CachingMetrics.cs +++ /dev/null @@ -1,10 +0,0 @@ -using SharpLab.Server.Monitoring; - -namespace SharpLab.Server.Caching { - public static class CachingMetrics { - public static MonitorMetric CacheableRequestCount { get; } = new("caching", "Caching: Cacheable Requests"); - public static MonitorMetric NoCacheRequestCount { get; } = new("caching", "Caching: No-Cache Requests"); - public static MonitorMetric BlobUploadRequestCount { get; } = new("caching", "Caching: Blob Upload Requests"); - public static MonitorMetric BlobUploadErrorCount { get; } = new("caching", "Caching: Blob Upload Errors"); - } -} diff --git a/source/Server/Caching/CachingModule.cs b/source/Server/Caching/CachingModule.cs index 494a36ae9..6cc682e94 100644 --- a/source/Server/Caching/CachingModule.cs +++ b/source/Server/Caching/CachingModule.cs @@ -3,21 +3,25 @@ using SharpLab.Server.Caching.Internal; using SharpLab.Server.Common; -namespace SharpLab.Server.Caching { - [UsedImplicitly] - public class CachingModule : Module { - protected override void Load(ContainerBuilder builder) { - var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); - var branchId = webAppName.StartsWith("sl-") ? webAppName : null; +namespace SharpLab.Server.Caching; - builder.RegisterType() - .As() - .WithParameter("branchId", branchId) - .SingleInstance(); +[UsedImplicitly] +public class CachingModule : Module { + protected override void Load(ContainerBuilder builder) { + var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); + var branchId = webAppName.StartsWith("sl-") ? webAppName : null; - builder.RegisterType() - .As() - .SingleInstance(); - } + builder.RegisterType() + .As() + .WithParameter("branchId", branchId) + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); } } \ No newline at end of file diff --git a/source/Server/Caching/CachingTracker.cs b/source/Server/Caching/CachingTracker.cs new file mode 100644 index 000000000..eae39bc55 --- /dev/null +++ b/source/Server/Caching/CachingTracker.cs @@ -0,0 +1,22 @@ +using SharpLab.Server.Monitoring; + +namespace SharpLab.Server.Caching; + +public class CachingTracker : ICachingTracker { + private readonly IZeroDimensionMetricMonitor _cacheableRequestCountMonitor; + private readonly IZeroDimensionMetricMonitor _noCacheRequestCountMonitor; + private readonly IZeroDimensionMetricMonitor _blobUploadRequestCountMonitor; + private readonly IZeroDimensionMetricMonitor _blobUploadErrorCountMonitor; + + public CachingTracker(IMonitor monitor) { + _cacheableRequestCountMonitor = monitor.MetricSlow("caching", "Caching: Cacheable Requests"); + _noCacheRequestCountMonitor = monitor.MetricSlow("caching", "Caching: No-Cache Requests"); + _blobUploadRequestCountMonitor = monitor.MetricSlow("caching", "Caching: Blob Upload Requests"); + _blobUploadErrorCountMonitor = monitor.MetricSlow("caching", "Caching: Blob Upload Errors"); + } + + public void TrackCacheableRequest() => _cacheableRequestCountMonitor.Track(1); + public void TrackNoCacheRequest() => _noCacheRequestCountMonitor.Track(1); + public void TrackBlobUploadRequest() => _blobUploadRequestCountMonitor.Track(1); + public void TrackBlobUploadError() => _blobUploadErrorCountMonitor.Track(1); +} diff --git a/source/Server/Caching/ICachingTracker.cs b/source/Server/Caching/ICachingTracker.cs new file mode 100644 index 000000000..66463d35b --- /dev/null +++ b/source/Server/Caching/ICachingTracker.cs @@ -0,0 +1,8 @@ +namespace SharpLab.Server.Caching; + +public interface ICachingTracker { + void TrackBlobUploadError(); + void TrackBlobUploadRequest(); + void TrackCacheableRequest(); + void TrackNoCacheRequest(); +} \ No newline at end of file diff --git a/source/Server/Caching/Internal/ResultCacheBuilder.cs b/source/Server/Caching/Internal/ResultCacheBuilder.cs index 0a56af5ad..b374f2ad5 100644 --- a/source/Server/Caching/Internal/ResultCacheBuilder.cs +++ b/source/Server/Caching/Internal/ResultCacheBuilder.cs @@ -5,6 +5,7 @@ namespace SharpLab.Server.Caching.Internal { public class ResultCacheBuilder : IResultCacheBuilder { + private const int AesGcmTagLength = 16; private readonly string? _branchId; private readonly MemoryPoolSlim _byteMemoryPool; private readonly byte[] _branchIdBytes; @@ -26,10 +27,10 @@ public ResultCacheDetails Build(in ResultCacheKeyData key, ReadOnlyMemory iv = _byteMemoryPool.RentExact(12); RandomNumberGenerator.Fill(iv.AsSpan()); - tag = _byteMemoryPool.RentExact(16); + tag = _byteMemoryPool.RentExact(AesGcmTagLength); encryptedData = _byteMemoryPool.RentExact(resultBytes.Length); - using (var aes = new AesGcm(secretKeyBytes)) + using (var aes = new AesGcm(secretKeyBytes, AesGcmTagLength)) aes.Encrypt(iv.AsSpan(), resultBytes.Span, encryptedData.AsSpan(), tag.AsSpan()); var publicHashBytes = (stackalloc byte[32]); diff --git a/source/Server/Common/CSharpTopLevelProgramSupport.cs b/source/Server/Common/CSharpTopLevelProgramSupport.cs index 69b22c870..102a3f17f 100644 --- a/source/Server/Common/CSharpTopLevelProgramSupport.cs +++ b/source/Server/Common/CSharpTopLevelProgramSupport.cs @@ -32,7 +32,7 @@ public void UpdateOutputKind(IWorkSession session, IList? diagnostic if (GlobalStatement == null) return; // this branch does not support global statements - if (session.GetTargetName() == TargetNames.Run) + if (session.GetTargetName() is TargetNames.Run or TargetNames.RunIL) return; // must always use executable mode for Run if (!session.Roslyn.Project.Documents.Single().TryGetSyntaxRoot(out var syntaxRoot)) { diff --git a/source/Server/Common/CommonModule.cs b/source/Server/Common/CommonModule.cs index 658c7fafe..22ddcb53d 100644 --- a/source/Server/Common/CommonModule.cs +++ b/source/Server/Common/CommonModule.cs @@ -8,75 +8,84 @@ using SharpLab.Server.Common.Languages; using SharpLab.Server.Compilation; -namespace SharpLab.Server.Common { - [UsedImplicitly] - public class CommonModule : Module { - protected override void Load(ContainerBuilder builder) { - RegisterExternals(builder); - - builder.RegisterInstance(MemoryPoolSlim.Shared); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - RegisterConfiguration(builder); - } - - private void RegisterConfiguration(ContainerBuilder builder) { - builder.RegisterType() - .As() - .SingleInstance() - .PreserveExistingDefaults(); - - builder.RegisterType() - .As() - .SingleInstance() - .PreserveExistingDefaults(); - } - - private void RegisterExternals(ContainerBuilder builder) { - builder.RegisterInstance(new RecyclableMemoryStreamManager()) - .AsSelf(); - - // older approach, needs to be updated to use factory now - builder.RegisterInstance>(() => new HttpClient()) - .As>() - .SingleInstance() - .PreserveExistingDefaults(); // allows tests and other overrides - - builder.RegisterType() - .As() - .SingleInstance(); - } +namespace SharpLab.Server.Common; +[UsedImplicitly] +public class CommonModule : Module { + protected override void Load(ContainerBuilder builder) { + RegisterExternals(builder); + + builder.RegisterInstance(MemoryPoolSlim.Shared); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + RegisterConfiguration(builder); + + var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); + builder.RegisterType() + .As() + .SingleInstance() + .WithParameter("webAppName", webAppName); + } + + private void RegisterConfiguration(ContainerBuilder builder) { + builder.RegisterType() + .As() + .SingleInstance() + .PreserveExistingDefaults(); + + builder.RegisterType() + .As() + .SingleInstance() + .PreserveExistingDefaults(); + } + + private void RegisterExternals(ContainerBuilder builder) { + builder.RegisterInstance(new RecyclableMemoryStreamManager()) + .AsSelf(); + + // older approach, needs to be updated to use factory now + builder.RegisterInstance>(() => new HttpClient()) + .As>() + .SingleInstance() + .PreserveExistingDefaults(); // allows tests and other overrides + + builder.RegisterType() + .As() + .SingleInstance(); } } diff --git a/source/Server/Common/Current.cs b/source/Server/Common/Current.cs index 0d57788c8..883c4a794 100644 --- a/source/Server/Common/Current.cs +++ b/source/Server/Common/Current.cs @@ -4,11 +4,7 @@ namespace SharpLab.Server.Common { public static class Current { - public static readonly int ProcessId = ((Func)(() => { - using (var current = Process.GetCurrentProcess()) { - return current.Id; - } - }))(); + public static readonly int ProcessId = Environment.ProcessId; public static readonly string AssemblyPath = typeof(Current).Assembly.GetAssemblyFile().FullName; } diff --git a/source/Server/Common/Diagnostics/AssemblyLog.cs b/source/Server/Common/Diagnostics/AssemblyLog.cs deleted file mode 100644 index 2e96d6dad..000000000 --- a/source/Server/Common/Diagnostics/AssemblyLog.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -#if DEBUG -using System.Threading; -#endif -using Mono.Cecil; - -namespace SharpLab.Server.Common.Diagnostics { - public static class AssemblyLog { - #if DEBUG - private static readonly AsyncLocal> _getPathByStepName = new(); - - public static void Enable(Func getPathByStepName) { - _getPathByStepName.Value = getPathByStepName; - } - #endif - - [Conditional("DEBUG")] - public static void Log(string stepName, AssemblyDefinition assembly) { - #if DEBUG - var path = GetLogPathWithoutExtension(stepName); - if (path == null) - return; - assembly.Write(path + ".dll"); - #endif - } - - public static void Log(string stepName, MemoryStream assemblyStream, MemoryStream? symbolStream) { - #if DEBUG - var path = GetLogPathWithoutExtension(stepName); - if (path == null) - return; - File.WriteAllBytes(path + ".dll", assemblyStream.ToArray()); - if (symbolStream != null) - File.WriteAllBytes(path + ".pdb", symbolStream.ToArray()); - #endif - } - - #if DEBUG - private static string? GetLogPathWithoutExtension(string stepName) { - if (_getPathByStepName.Value is not {} getPathByStepName) - return null; - - var path = getPathByStepName(stepName); - var directoryPath = Path.GetDirectoryName(path); - if (directoryPath != null && !Directory.Exists(directoryPath)) - Directory.CreateDirectory(directoryPath); - return path; - } - #endif - } -} diff --git a/source/Server/Common/Diagnostics/DiagnosticLog.cs b/source/Server/Common/Diagnostics/DiagnosticLog.cs new file mode 100644 index 000000000..9cd273030 --- /dev/null +++ b/source/Server/Common/Diagnostics/DiagnosticLog.cs @@ -0,0 +1,60 @@ +#if DEBUG +using System; +using System.IO; +using System.Threading; +using Mono.Cecil; + +namespace SharpLab.Server.Common.Diagnostics; + +public static class DiagnosticLog { + private static readonly AsyncLocal> _getPathByStepName = new(); + private static readonly AsyncLocal> _logMessage = new(); + + public static void Enable(Action logMessage, Func getPathByStepName) { + _logMessage.Value = logMessage; + _getPathByStepName.Value = getPathByStepName; + } + + public static bool IsEnabled() { + return _getPathByStepName.Value != null; + } + + public static void LogMessage(string message) { + _logMessage.Value?.Invoke(message); + } + + public static void LogAssembly(string stepName, ModuleDefinition module) { + var path = GetLogPathWithoutExtension(stepName); + if (path == null) + return; + module.Write(path + ".dll"); + } + + public static void LogAssembly(string stepName, MemoryStream assemblyStream, MemoryStream? symbolStream) { + var path = GetLogPathWithoutExtension(stepName); + if (path == null) + return; + File.WriteAllBytes(path + ".dll", assemblyStream.ToArray()); + if (symbolStream != null) + File.WriteAllBytes(path + ".pdb", symbolStream.ToArray()); + } + + public static void LogText(string stepName, string text) { + var path = GetLogPathWithoutExtension(stepName); + if (path == null) + return; + File.WriteAllText(path + ".txt", text); + } + + private static string? GetLogPathWithoutExtension(string stepName) { + if (_getPathByStepName.Value is not {} getPathByStepName) + return null; + + var path = getPathByStepName(stepName); + var directoryPath = Path.GetDirectoryName(path); + if (directoryPath != null && !Directory.Exists(directoryPath)) + Directory.CreateDirectory(directoryPath); + return path; + } +} +#endif \ No newline at end of file diff --git a/source/Server/Common/EnvironmentHelper.cs b/source/Server/Common/EnvironmentHelper.cs index 4101c5598..60b045702 100644 --- a/source/Server/Common/EnvironmentHelper.cs +++ b/source/Server/Common/EnvironmentHelper.cs @@ -1,10 +1,10 @@ using System; -namespace SharpLab.Server.Common { - public static class EnvironmentHelper { - public static string GetRequiredEnvironmentVariable(string name) { - return Environment.GetEnvironmentVariable(name) - ?? throw new Exception($"Environment variable {name} was not found"); - } +namespace SharpLab.Server.Common; + +public static class EnvironmentHelper { + public static string GetRequiredEnvironmentVariable(string name) { + return Environment.GetEnvironmentVariable(name) + ?? throw new Exception($"Environment variable {name} was not found"); } } diff --git a/source/Server/Common/ExceptionLogFilter.cs b/source/Server/Common/ExceptionLogFilter.cs new file mode 100644 index 000000000..965c6ec71 --- /dev/null +++ b/source/Server/Common/ExceptionLogFilter.cs @@ -0,0 +1,19 @@ +using MirrorSharp.Advanced; +using System; +using System.Net.WebSockets; + +namespace SharpLab.Server.Common { + public class ExceptionLogFilter : IExceptionLogFilter { + public bool ShouldLog(Exception exception, IWorkSession session) { + // Note/TODO: need to see if OperationCanceledException can be avoided + // https://github.com/ashmind/SharpLab/issues/617 + if (exception is WebSocketException or OperationCanceledException) + return false; + + if (session.LanguageName == LanguageNames.IL && session.GetText().Contains(".emitbyte") && exception is BadImageFormatException) + return false; // 🤷 emit byte, break assembly + + return true; + } + } +} \ No newline at end of file diff --git a/source/Server/Common/FeatureTracker.cs b/source/Server/Common/FeatureTracker.cs new file mode 100644 index 000000000..f59ec2868 --- /dev/null +++ b/source/Server/Common/FeatureTracker.cs @@ -0,0 +1,35 @@ +using SharpLab.Server.Monitoring; + +namespace SharpLab.Server.Common; + +public class FeatureTracker : IFeatureTracker { + private readonly string _webAppName; + private readonly IOneDimensionMetricMonitor _branchMetricMonitor; + private readonly IOneDimensionMetricMonitor _languageMetricMonitor; + private readonly IOneDimensionMetricMonitor _targetMetricMonitor; + private readonly IOneDimensionMetricMonitor _optimizeMetricMonitor; + + public FeatureTracker(IMonitor monitor, string webAppName) { + _webAppName = webAppName; + _branchMetricMonitor = monitor.MetricSlow("feature", "Branch", "Branch"); + _languageMetricMonitor = monitor.MetricSlow("feature", "Language", "Language"); + _targetMetricMonitor = monitor.MetricSlow("feature", "Target", "Target"); + _optimizeMetricMonitor = monitor.MetricSlow("feature", "Optimize", "Optimize"); + } + + public void TrackBranch() { + _branchMetricMonitor.Track(_webAppName, 1); + } + + public void TrackLanguage(string languageName) { + _languageMetricMonitor.Track(languageName, 1); + } + + public void TrackTarget(string targetName) { + _targetMetricMonitor.Track(targetName, 1); + } + + public void TrackOptimize(string optimize) { + _optimizeMetricMonitor.Track(optimize, 1); + } +} diff --git a/source/Server/Common/IExceptionLogFilter.cs b/source/Server/Common/IExceptionLogFilter.cs new file mode 100644 index 000000000..69fea1617 --- /dev/null +++ b/source/Server/Common/IExceptionLogFilter.cs @@ -0,0 +1,8 @@ +using MirrorSharp.Advanced; +using System; + +namespace SharpLab.Server.Common { + public interface IExceptionLogFilter { + bool ShouldLog(Exception exception, IWorkSession session); + } +} diff --git a/source/Server/Common/IFeatureTracker.cs b/source/Server/Common/IFeatureTracker.cs new file mode 100644 index 000000000..373ce9b7c --- /dev/null +++ b/source/Server/Common/IFeatureTracker.cs @@ -0,0 +1,8 @@ +namespace SharpLab.Server.Common; + +public interface IFeatureTracker { + void TrackBranch(); + void TrackLanguage(string languageName); + void TrackTarget(string targetName); + void TrackOptimize(string optimize); +} \ No newline at end of file diff --git a/source/Server/Common/ILanguageAdapter.cs b/source/Server/Common/ILanguageAdapter.cs index 8fe919dfe..02b2db209 100644 --- a/source/Server/Common/ILanguageAdapter.cs +++ b/source/Server/Common/ILanguageAdapter.cs @@ -3,18 +3,17 @@ using MirrorSharp.Advanced; using SharpLab.Server.Common.Internal; -namespace SharpLab.Server.Common { - public interface ILanguageAdapter { - string LanguageName { get; } +namespace SharpLab.Server.Common; +public interface ILanguageAdapter { + string LanguageName { get; } - void SlowSetup(MirrorSharpOptions options); - void SetOptimize(IWorkSession session, string optimize); - void SetOptionsForTarget(IWorkSession session, string target); + void SlowSetup(MirrorSharpOptions options); + void SetOptimize(IWorkSession session, string optimize); + void SetOptionsForTarget(IWorkSession session, string target); - ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod); - ImmutableArray GetCallArgumentIdentifiers(IWorkSession session, int callStartLine, int callStartColumn); + ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod); + ImmutableArray GetCallArgumentIdentifiers(IWorkSession session, int callStartLine, int callStartColumn); - // Note: in some cases this Task is never resolved (e.g. if VB is never used) - AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } - } + // Note: in some cases this Task is never resolved (e.g. if VB is never used) + AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } } \ No newline at end of file diff --git a/source/Server/Common/ISecretsClient.cs b/source/Server/Common/ISecretsClient.cs index 676980357..1d5f5c85a 100644 --- a/source/Server/Common/ISecretsClient.cs +++ b/source/Server/Common/ISecretsClient.cs @@ -1,5 +1,5 @@ -namespace SharpLab.Server.Common { - public interface ISecretsClient { - string GetSecret(string key); - } +namespace SharpLab.Server.Common; + +public interface ISecretsClient { + string GetSecret(string key); } \ No newline at end of file diff --git a/source/Server/Common/LanguageNames.cs b/source/Server/Common/LanguageNames.cs index c2ec52785..54ed93db4 100644 --- a/source/Server/Common/LanguageNames.cs +++ b/source/Server/Common/LanguageNames.cs @@ -1,10 +1,10 @@ using CodeAnalysis = Microsoft.CodeAnalysis; -namespace SharpLab.Server.Common { - public class LanguageNames { - public const string CSharp = CodeAnalysis.LanguageNames.CSharp; - public const string VisualBasic = CodeAnalysis.LanguageNames.VisualBasic; - public const string FSharp = CodeAnalysis.LanguageNames.FSharp; - public const string IL = "IL"; - } +namespace SharpLab.Server.Common; + +public class LanguageNames { + public const string CSharp = CodeAnalysis.LanguageNames.CSharp; + public const string VisualBasic = CodeAnalysis.LanguageNames.VisualBasic; + public const string FSharp = CodeAnalysis.LanguageNames.FSharp; + public const string IL = "IL"; } diff --git a/source/Server/Common/Languages/CSharpAdapter.cs b/source/Server/Common/Languages/CSharpAdapter.cs index d6816bea2..4f748773a 100644 --- a/source/Server/Common/Languages/CSharpAdapter.cs +++ b/source/Server/Common/Languages/CSharpAdapter.cs @@ -13,141 +13,145 @@ using SharpLab.Server.Compilation; using SharpLab.Server.Compilation.Internal; -namespace SharpLab.Server.Common.Languages { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class CSharpAdapter : ILanguageAdapter { - private static readonly LanguageVersion MaxLanguageVersion = Enum - .GetValues(typeof (LanguageVersion)) - .Cast() - .Where(v => v != LanguageVersion.Latest) // seems like latest got fixed at some point - .Max(); - private static readonly ImmutableArray ReleasePreprocessorSymbols = PreprocessorSymbols.Release.Add("__DEMO_EXPERIMENTAL__"); - private static readonly ImmutableArray DebugPreprocessorSymbols = PreprocessorSymbols.Debug.Add("__DEMO_EXPERIMENTAL__"); - - private readonly ImmutableList _references; - private readonly ICSharpTopLevelProgramSupport _topLevelProgramSupport; - - public CSharpAdapter( - IAssemblyPathCollector assemblyPathCollector, - IAssemblyDocumentationResolver documentationResolver, - ICSharpTopLevelProgramSupport topLevelProgramSupport - ) { - var referencedAssemblyPaths = assemblyPathCollector.SlowGetAllAssemblyPathsIncludingReferences( - // Essential - NetFrameworkRuntime.AssemblyOfValueTask.GetName().Name!, - NetFrameworkRuntime.AssemblyOfValueTuple.GetName().Name!, - NetFrameworkRuntime.AssemblyOfSpan.GetName().Name!, - "Microsoft.CSharp", - - // Runtime - "SharpLab.Runtime", - - // Requested - "System.Data", - "System.Runtime.Intrinsics", - "System.Web.HttpUtility", - "System.Xml.Linq" - ).ToImmutableList(); - - var assemblyReferenceTaskSource = new AssemblyReferenceDiscoveryTaskSource(); - assemblyReferenceTaskSource.Complete(referencedAssemblyPaths); - AssemblyReferenceDiscoveryTask = assemblyReferenceTaskSource.Task; - - _references = referencedAssemblyPaths - .Select(path => (MetadataReference)MetadataReference.CreateFromFile(path, documentation: documentationResolver.GetDocumentation(path))) - .ToImmutableList(); - _topLevelProgramSupport = topLevelProgramSupport; - } +namespace SharpLab.Server.Common.Languages; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class CSharpAdapter : ILanguageAdapter { + private static readonly LanguageVersion MaxLanguageVersion = Enum + .GetValues(typeof (LanguageVersion)) + .Cast() + .Where(v => v != LanguageVersion.Latest) // seems like latest got fixed at some point + .Max(); + private static readonly ImmutableArray ReleasePreprocessorSymbols = PreprocessorSymbols.Release.Add("__DEMO_EXPERIMENTAL__"); + private static readonly ImmutableArray DebugPreprocessorSymbols = PreprocessorSymbols.Debug.Add("__DEMO_EXPERIMENTAL__"); + + private readonly ImmutableList _references; + private readonly ICSharpTopLevelProgramSupport _topLevelProgramSupport; + + public CSharpAdapter( + IAssemblyPathCollector assemblyPathCollector, + IAssemblyDocumentationResolver documentationResolver, + ICSharpTopLevelProgramSupport topLevelProgramSupport + ) { + var referencedAssemblyPaths = assemblyPathCollector.SlowGetAllAssemblyPathsIncludingReferences( + // Essential + NetFrameworkRuntime.AssemblyOfValueTask.GetName().Name!, + NetFrameworkRuntime.AssemblyOfValueTuple.GetName().Name!, + NetFrameworkRuntime.AssemblyOfSpan.GetName().Name!, + "Microsoft.CSharp", + + // Runtime + "SharpLab.Runtime", + + // Requested + "System.Collections.Immutable", + "System.Data", + "System.Runtime.CompilerServices.Unsafe", + "System.Runtime.Intrinsics", + "System.Text.Json", + "System.Web.HttpUtility", + "System.Xml.Linq" + ).ToImmutableList(); + + var assemblyReferenceTaskSource = new AssemblyReferenceDiscoveryTaskSource(); + assemblyReferenceTaskSource.Complete(referencedAssemblyPaths); + AssemblyReferenceDiscoveryTask = assemblyReferenceTaskSource.Task; + + _references = referencedAssemblyPaths + .Select(path => (MetadataReference)MetadataReference.CreateFromFile(path, documentation: documentationResolver.GetDocumentation(path))) + .ToImmutableList(); + _topLevelProgramSupport = topLevelProgramSupport; + } - public string LanguageName => LanguageNames.CSharp; - public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } - - public void SlowSetup(MirrorSharpOptions options) { - // ReSharper disable HeapView.ObjectAllocation.Evident - - options.CSharp.ParseOptions = new CSharpParseOptions( - MaxLanguageVersion, - preprocessorSymbols: DebugPreprocessorSymbols, - documentationMode: DocumentationMode.Diagnose - ); - options.CSharp.CompilationOptions = new CSharpCompilationOptions( - OutputKind.DynamicallyLinkedLibrary, - specificDiagnosticOptions: new Dictionary { - // CS1591: Missing XML comment for publicly visible type or member - { "CS1591", ReportDiagnostic.Suppress } - }, - allowUnsafe: true - ); - options.CSharp.MetadataReferences = _references; - - // ReSharper restore HeapView.ObjectAllocation.Evident - } + public string LanguageName => LanguageNames.CSharp; + public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask { get; } + + public void SlowSetup(MirrorSharpOptions options) { + // ReSharper disable HeapView.ObjectAllocation.Evident + + options.CSharp.ParseOptions = new CSharpParseOptions( + MaxLanguageVersion, + preprocessorSymbols: DebugPreprocessorSymbols, + documentationMode: DocumentationMode.Diagnose + ); + options.CSharp.CompilationOptions = new CSharpCompilationOptions( + OutputKind.DynamicallyLinkedLibrary, + specificDiagnosticOptions: new Dictionary { + // CS1591: Missing XML comment for publicly visible type or member + { "CS1591", ReportDiagnostic.Suppress } + }, + allowUnsafe: true, + nullableContextOptions: NullableContextOptions.Enable + ); + options.CSharp.MetadataReferences = _references; + + // ReSharper restore HeapView.ObjectAllocation.Evident + } - public void SetOptimize(IWorkSession session, string optimize) { - var project = session.Roslyn.Project; - var parseOptions = ((CSharpParseOptions)project.ParseOptions!); - var compilationOptions = ((CSharpCompilationOptions)project.CompilationOptions!); - session.Roslyn.Project = project - .WithParseOptions(parseOptions.WithPreprocessorSymbols(optimize == Optimize.Debug ? DebugPreprocessorSymbols : ReleasePreprocessorSymbols)) - .WithCompilationOptions(compilationOptions.WithOptimizationLevel(optimize == Optimize.Debug ? OptimizationLevel.Debug : OptimizationLevel.Release)); - } + public void SetOptimize(IWorkSession session, string optimize) { + var project = session.Roslyn.Project; + var parseOptions = ((CSharpParseOptions)project.ParseOptions!); + var compilationOptions = ((CSharpCompilationOptions)project.CompilationOptions!); + session.Roslyn.Project = project + .WithParseOptions(parseOptions.WithPreprocessorSymbols(optimize == Optimize.Debug ? DebugPreprocessorSymbols : ReleasePreprocessorSymbols)) + .WithCompilationOptions(compilationOptions.WithOptimizationLevel(optimize == Optimize.Debug ? OptimizationLevel.Debug : OptimizationLevel.Release)); + } - public void SetOptionsForTarget(IWorkSession session, string target) { - var outputKind = target != TargetNames.Run - ? OutputKind.DynamicallyLinkedLibrary - : OutputKind.ConsoleApplication; + public void SetOptionsForTarget(IWorkSession session, string target) { + var outputKind = target is TargetNames.Run or TargetNames.RunIL + ? OutputKind.ConsoleApplication + : OutputKind.DynamicallyLinkedLibrary; - var project = session.Roslyn.Project; - var options = ((CSharpCompilationOptions)project.CompilationOptions!); - session.Roslyn.Project = project.WithCompilationOptions( - options.WithOutputKind(outputKind) - ); + var project = session.Roslyn.Project; + var options = ((CSharpCompilationOptions)project.CompilationOptions!); + session.Roslyn.Project = project.WithCompilationOptions( + options.WithOutputKind(outputKind) + ); - _topLevelProgramSupport.UpdateOutputKind(session); - } + _topLevelProgramSupport.UpdateOutputKind(session); + } - public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { - var declaration = RoslynAdapterHelper.FindSyntaxNodeInSession(session, lineInMethod, columnInMethod) - ?.AncestorsAndSelf() - .FirstOrDefault(m => m is MemberDeclarationSyntax - || m is AnonymousFunctionExpressionSyntax - || m is LocalFunctionStatementSyntax); - - var parameters = declaration switch { - BaseMethodDeclarationSyntax m => m.ParameterList.Parameters, - ParenthesizedLambdaExpressionSyntax l => l.ParameterList.Parameters, - SimpleLambdaExpressionSyntax l => SyntaxFactory.SingletonSeparatedList(l.Parameter), - LocalFunctionStatementSyntax f => f.ParameterList.Parameters, - _ => SyntaxFactory.SeparatedList() - }; - - if (parameters.Count == 0) - return ImmutableArray.Empty; - - var results = new int[parameters.Count]; - for (var i = 0; i < parameters.Count; i++) { - results[i] = parameters[i].GetLocation().GetLineSpan().StartLinePosition.Line + 1; - } - return ImmutableArray.Create(results); + public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { + var declaration = RoslynAdapterHelper.FindSyntaxNodeInSession(session, lineInMethod, columnInMethod) + ?.AncestorsAndSelf() + .FirstOrDefault(m => m is MemberDeclarationSyntax + || m is AnonymousFunctionExpressionSyntax + || m is LocalFunctionStatementSyntax); + + var parameters = declaration switch { + BaseMethodDeclarationSyntax m => m.ParameterList.Parameters, + ParenthesizedLambdaExpressionSyntax l => l.ParameterList.Parameters, + SimpleLambdaExpressionSyntax l => SyntaxFactory.SingletonSeparatedList(l.Parameter), + LocalFunctionStatementSyntax f => f.ParameterList.Parameters, + _ => SyntaxFactory.SeparatedList() + }; + + if (parameters.Count == 0) + return []; + + var results = new int[parameters.Count]; + for (var i = 0; i < parameters.Count; i++) { + results[i] = parameters[i].GetLocation().GetLineSpan().StartLinePosition.Line + 1; } + return ImmutableArray.Create(results); + } - public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { - var call = RoslynAdapterHelper.FindSyntaxNodeInSession(session, callStartLine, callStartColumn) - ?.AncestorsAndSelf() - .OfType() - .FirstOrDefault(); - if (call == null) - return ImmutableArray.Empty; - - var arguments = call.ArgumentList.Arguments; - if (arguments.Count == 0) - return ImmutableArray.Empty; - - var results = new string?[arguments.Count]; - for (var i = 0; i < arguments.Count; i++) { - results[i] = (arguments[i].Expression is IdentifierNameSyntax n) ? n.Identifier.ValueText : null; - } - return ImmutableArray.Create(results); + public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { + var call = RoslynAdapterHelper.FindSyntaxNodeInSession(session, callStartLine, callStartColumn) + ?.AncestorsAndSelf() + .OfType() + .FirstOrDefault(); + if (call == null) + return []; + + var arguments = call.ArgumentList.Arguments; + if (arguments.Count == 0) + return []; + + var results = new string?[arguments.Count]; + for (var i = 0; i < arguments.Count; i++) { + results[i] = (arguments[i].Expression is IdentifierNameSyntax n) ? n.Identifier.ValueText : null; } + return ImmutableArray.Create(results); } } diff --git a/source/Server/Common/Languages/FSharpAdapter.cs b/source/Server/Common/Languages/FSharpAdapter.cs index 598d1239b..ea50f5554 100644 --- a/source/Server/Common/Languages/FSharpAdapter.cs +++ b/source/Server/Common/Languages/FSharpAdapter.cs @@ -5,64 +5,66 @@ using MirrorSharp.FSharp.Advanced; using SharpLab.Server.Common.Internal; -namespace SharpLab.Server.Common.Languages { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class FSharpAdapter : ILanguageAdapter { - private readonly AssemblyReferenceDiscoveryTaskSource _referencedAssembliesTaskSource = new(); - private readonly IAssemblyPathCollector _assemblyPathCollector; +namespace SharpLab.Server.Common.Languages; - public string LanguageName => LanguageNames.FSharp; - public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask => _referencedAssembliesTaskSource.Task; +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class FSharpAdapter : ILanguageAdapter { + private readonly AssemblyReferenceDiscoveryTaskSource _referencedAssembliesTaskSource = new(); + private readonly IAssemblyPathCollector _assemblyPathCollector; - public FSharpAdapter(IAssemblyPathCollector assemblyPathCollector) { - _assemblyPathCollector = assemblyPathCollector; - } + public string LanguageName => LanguageNames.FSharp; + public AssemblyReferenceDiscoveryTask AssemblyReferenceDiscoveryTask => _referencedAssembliesTaskSource.Task; - public void SlowSetup(MirrorSharpOptions options) { - options.EnableFSharp(o => { - o.LangVersion = "preview"; + public FSharpAdapter(IAssemblyPathCollector assemblyPathCollector) { + _assemblyPathCollector = assemblyPathCollector; + } + + public void SlowSetup(MirrorSharpOptions options) { + options.EnableFSharp(o => { + o.LangVersion = "preview"; - var referencedAssemblyPaths = _assemblyPathCollector.SlowGetAllAssemblyPathsIncludingReferences( - // Essential - "netstandard", - "System.Runtime", - "FSharp.Core", + var referencedAssemblyPaths = _assemblyPathCollector.SlowGetAllAssemblyPathsIncludingReferences( + // Essential + "netstandard", + "System.Runtime", + "FSharp.Core", - // Runtime - "SharpLab.Runtime", + // Runtime + "SharpLab.Runtime", - // Requested - "System.Data", - "System.Runtime.Intrinsics", - "System.Web.HttpUtility", - "System.Xml.Linq" - ).ToImmutableArray(); - _referencedAssembliesTaskSource.Complete(referencedAssemblyPaths); + // Requested + "System.Collections.Immutable", + "System.Data", + "System.Runtime.CompilerServices.Unsafe", + "System.Runtime.Intrinsics", + "System.Text.Json", + "System.Web.HttpUtility", + "System.Xml.Linq" + ).ToImmutableArray(); + _referencedAssembliesTaskSource.Complete(referencedAssemblyPaths); - o.AssemblyReferencePaths = referencedAssemblyPaths; - o.TargetProfile = "netstandard"; - }); - } + o.AssemblyReferencePaths = referencedAssemblyPaths; + o.TargetProfile = "netstandard"; + }); + } - public void SetOptimize([NotNull] IWorkSession session, [NotNull] string optimize) { - var debug = optimize == Optimize.Debug; - var fsharp = session.FSharp(); - fsharp.ProjectOptions = fsharp.ProjectOptions - .WithOtherOptionDebug(debug) - .WithOtherOptionOptimize(!debug) - .WithOtherOptionDefine("DEBUG", debug); - } + public void SetOptimize([NotNull] IWorkSession session, [NotNull] string optimize) { + var debug = optimize == Optimize.Debug; + var fsharp = session.FSharp(); + fsharp.ProjectOptions = fsharp.ProjectOptions + .WithOtherOptionOptimize(!debug) + .WithOtherOptionDefine("DEBUG", debug); + } - public void SetOptionsForTarget([NotNull] IWorkSession session, [NotNull] string target) { - // I don't use `exe` for Run, see FSharpEntryPointRewriter - } + public void SetOptionsForTarget([NotNull] IWorkSession session, [NotNull] string target) { + // I don't use `exe` for Run, see FSharpEntryPointRewriter + } - public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { - return ImmutableArray.Empty; // not supported yet - } + public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { + return []; // not supported yet + } - public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { - return ImmutableArray.Empty; // not supported yet - } + public ImmutableArray GetCallArgumentIdentifiers([NotNull] IWorkSession session, int callStartLine, int callStartColumn) { + return []; // not supported yet } } \ No newline at end of file diff --git a/source/Server/Common/Languages/ILAdapter.cs b/source/Server/Common/Languages/ILAdapter.cs index 167b6fe04..b5c3d0cc7 100644 --- a/source/Server/Common/Languages/ILAdapter.cs +++ b/source/Server/Common/Languages/ILAdapter.cs @@ -21,7 +21,9 @@ public void SetOptimize(IWorkSession session, string optimize) { } public void SetOptionsForTarget(IWorkSession session, string target) { - session.IL().Target = target == TargetNames.Run ? Driver.Target.Exe : Driver.Target.Dll; + session.IL().Target = target is TargetNames.Run or TargetNames.RunIL + ? Driver.Target.Exe + : Driver.Target.Dll; } public ImmutableArray GetMethodParameterLines(IWorkSession session, int lineInMethod, int columnInMethod) { diff --git a/source/Server/Common/Languages/VisualBasicAdapter.cs b/source/Server/Common/Languages/VisualBasicAdapter.cs index c12ee90aa..2a0c0a490 100644 --- a/source/Server/Common/Languages/VisualBasicAdapter.cs +++ b/source/Server/Common/Languages/VisualBasicAdapter.cs @@ -52,8 +52,11 @@ public void SlowSetup(MirrorSharpOptions options) { "SharpLab.Runtime", // Requested + "System.Collections.Immutable", "System.Data", + "System.Runtime.CompilerServices.Unsafe", "System.Runtime.Intrinsics", + "System.Text.Json", "System.Web.HttpUtility", "System.Xml.Linq" ).ToImmutableList(); @@ -76,7 +79,9 @@ public void SetOptimize(IWorkSession session, string optimize) { } public void SetOptionsForTarget(IWorkSession session, string target) { - var outputKind = target != TargetNames.Run ? OutputKind.DynamicallyLinkedLibrary : OutputKind.ConsoleApplication; + var outputKind = target is TargetNames.Run or TargetNames.RunIL + ? OutputKind.ConsoleApplication + : OutputKind.DynamicallyLinkedLibrary; var project = session.Roslyn.Project; var options = ((VisualBasicCompilationOptions)project.CompilationOptions!); diff --git a/source/Server/Common/Optimize.cs b/source/Server/Common/Optimize.cs index daf0b91ec..d4b107e1b 100644 --- a/source/Server/Common/Optimize.cs +++ b/source/Server/Common/Optimize.cs @@ -1,6 +1,5 @@ -namespace SharpLab.Server.Common { - public static class Optimize { - public const string Debug = "debug"; - public const string Release = "release"; - } +namespace SharpLab.Server.Common; +public static class Optimize { + public const string Debug = "debug"; + public const string Release = "release"; } diff --git a/source/Server/Common/TargetNames.cs b/source/Server/Common/TargetNames.cs index 2845dc0b3..aeff69bf1 100644 --- a/source/Server/Common/TargetNames.cs +++ b/source/Server/Common/TargetNames.cs @@ -1,11 +1,12 @@ -namespace SharpLab.Server.Common { - public static class TargetNames { - public const string CSharp = LanguageNames.CSharp; - public const string IL = LanguageNames.IL; - public const string Ast = "AST"; - public const string JitAsm = "JIT ASM"; - public const string Run = "Run"; - public const string Verify = "Verify"; - public const string Explain = "Explain"; - } +namespace SharpLab.Server.Common; + +public static class TargetNames { + public const string CSharp = LanguageNames.CSharp; + public const string IL = LanguageNames.IL; + public const string Ast = "AST"; + public const string JitAsm = "JIT ASM"; + public const string Run = "Run"; + public const string RunIL = "Run IL"; + public const string Verify = "Verify"; + public const string Explain = "Explain"; } \ No newline at end of file diff --git a/source/Server/Compilation/Compiler.cs b/source/Server/Compilation/Compiler.cs index f0f233dc7..de97a9f23 100644 --- a/source/Server/Compilation/Compiler.cs +++ b/source/Server/Compilation/Compiler.cs @@ -5,11 +5,8 @@ using System.Threading; using System.Threading.Tasks; using FSharp.Compiler.Diagnostics; -using FSharp.Compiler.Syntax; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; -using Microsoft.FSharp.Collections; -using Microsoft.FSharp.Control; using Microsoft.IO; using MirrorSharp.Advanced; using MirrorSharp.FSharp.Advanced; @@ -18,104 +15,93 @@ using Mobius.ILasm.Core; using SharpLab.Server.Compilation.Internal; -namespace SharpLab.Server.Compilation { - public class Compiler : ICompiler { - private static readonly EmitOptions RoslynEmitOptions = new( - // TODO: try out embedded - debugInformationFormat: DebugInformationFormat.PortablePdb - ); - private readonly RecyclableMemoryStreamManager _memoryStreamManager; +namespace SharpLab.Server.Compilation; - public Compiler(RecyclableMemoryStreamManager memoryStreamManager) { - _memoryStreamManager = memoryStreamManager; - } +public class Compiler : ICompiler { + private static readonly EmitOptions RoslynEmitOptions = new( + // TODO: try out embedded + debugInformationFormat: DebugInformationFormat.PortablePdb + ); + private readonly RecyclableMemoryStreamManager _memoryStreamManager; - public async Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( - MemoryStream assemblyStream, - MemoryStream? symbolStream, - IWorkSession session, - IList diagnostics, - CancellationToken cancellationToken - ) { - if (session.IsFSharp()) { - var compiled = await TryCompileFSharpToStreamAsync(assemblyStream, session, diagnostics, cancellationToken).ConfigureAwait(false); - return (compiled, false); - } + public Compiler(RecyclableMemoryStreamManager memoryStreamManager) { + _memoryStreamManager = memoryStreamManager; + } - if (session.IsIL()) { - var compiled = TryCompileILToStream(assemblyStream, session, diagnostics); - return (compiled, false); - } + public async Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( + MemoryStream assemblyStream, + MemoryStream? symbolStream, + IWorkSession session, + IList diagnostics, + CancellationToken cancellationToken + ) { + if (session.IsFSharp()) { + var compiled = await TryCompileFSharpToStreamAsync(assemblyStream, session, diagnostics, cancellationToken).ConfigureAwait(false); + return (compiled, false); + } - #warning TODO: Revisit after https: //github.com/dotnet/docs/issues/14784 - var compilation = (await session.Roslyn.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; - var emitResult = compilation.Emit(assemblyStream, pdbStream: symbolStream, options: RoslynEmitOptions); - if (!emitResult.Success) { - foreach (var diagnostic in emitResult.Diagnostics) { - diagnostics.Add(diagnostic); - } + if (session.IsIL()) { + var compiled = TryCompileILToStream(assemblyStream, session, diagnostics); + return (compiled, false); + } - return (false, false); + #warning TODO: Revisit after https: //github.com/dotnet/docs/issues/14784 + var compilation = (await session.Roslyn.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false))!; + var emitResult = compilation.Emit(assemblyStream, pdbStream: symbolStream, options: RoslynEmitOptions); + if (!emitResult.Success) { + foreach (var diagnostic in emitResult.Diagnostics) { + diagnostics.Add(diagnostic); } - return (true, true); + return (false, false); } - private async Task TryCompileFSharpToStreamAsync( - MemoryStream assemblyStream, - IWorkSession session, - IList diagnostics, - CancellationToken cancellationToken - ) { - var fsharp = session.FSharp(); + return (true, true); + } - // GetLastParseResults are guaranteed to be available here as MirrorSharp's SlowUpdate does the parse - var parsed = fsharp.GetLastParseResults()!; - using (var virtualAssemblyFile = FSharpFileSystem.RegisterVirtualFile(assemblyStream)) { - var compiled = await FSharpAsync.StartAsTask(fsharp.Checker.Compile( - FSharpList.Cons(parsed.ParseTree, FSharpList.Empty), - "_", virtualAssemblyFile.Path, - fsharp.AssemblyReferencePathsAsFSharpList, - pdbFile: null, - executable: false, //fsharp.ProjectOptions.OtherOptions.Contains("--target:exe"), - noframework: true, - userOpName: null - ), null, cancellationToken).ConfigureAwait(false); - foreach (var diagnostic in compiled.Item1) { - // no reason to add warnings as check would have added them anyways - if (diagnostic.Severity.Tag == FSharpDiagnosticSeverity.Tags.Error) - diagnostics.Add(fsharp.ConvertToDiagnostic(diagnostic)); - } + private async ValueTask TryCompileFSharpToStreamAsync( + MemoryStream assemblyStream, + IWorkSession session, + IList diagnostics, + CancellationToken cancellationToken + ) { + var fsharp = session.FSharp(); + var compiled = await fsharp.CompileAsync(assemblyStream, cancellationToken) + .ConfigureAwait(false); - return assemblyStream.Length > 0; - } + foreach (var diagnostic in compiled.Item1) { + // no reason to add warnings as check would have added them anyways + if (diagnostic.Severity.Tag == FSharpDiagnosticSeverity.Tags.Error) + diagnostics.Add(fsharp.ConvertToDiagnostic(diagnostic)); } - private static readonly DriverSettings ILDriverSettings = new() { - ResourceResolver = ILNullResourceResolver.Default - }; - private bool TryCompileILToStream(MemoryStream assemblyStream, IWorkSession session, IList diagnostics) { - var il = (IILSessionInternal)session.IL(); - var ilText = il.GetTextBuilderForReadsOnly(); + return assemblyStream.Length > 0; + } - // TODO: See if we can get offset from the library instead - var lineColumnMap = ILLineColumnMap.BuildFor(ilText); - var logger = new ILCompilationLogger(diagnostics, lineColumnMap); - var driver = new Driver(logger, il.Target, ILDriverSettings); + private static readonly DriverSettings ILDriverSettings = new() { + ResourceResolver = ILNullResourceResolver.Default + }; + private bool TryCompileILToStream(MemoryStream assemblyStream, IWorkSession session, IList diagnostics) { + var il = (IILSessionInternal)session.IL(); + var ilText = il.GetTextBuilderForReadsOnly(); - using var sourceStream = (RecyclableMemoryStream)_memoryStreamManager.GetStream("Compiler-IL", il.TextLength); - foreach (var chunk in ilText.GetChunks()) { - Encoding.UTF8.GetBytes(chunk.Span, sourceStream); - } - sourceStream.Position = 0; + // TODO: See if we can get offset from the library instead + var lineColumnMap = ILLineColumnMap.BuildFor(ilText); + var logger = new ILCompilationLogger(diagnostics, lineColumnMap); + var driver = new Driver(logger, il.Target, ILDriverSettings); - try { - return driver.Assemble(new[] { sourceStream }, assemblyStream); - } - catch (Exception ex) when (ex.GetType().Name.StartsWith("yy")) { - // These are also reported through the logger, so will be reported as diagnostics - return false; - } + using var sourceStream = (RecyclableMemoryStream)_memoryStreamManager.GetStream("Compiler-IL", il.TextLength); + foreach (var chunk in ilText.GetChunks()) { + Encoding.UTF8.GetBytes(chunk.Span, sourceStream); + } + sourceStream.Position = 0; + + try { + return driver.Assemble(new[] { sourceStream }, assemblyStream); + } + catch (Exception ex) when (ex.GetType().Name.StartsWith("yy")) { + // These are also reported through the logger, so will be reported as diagnostics + return false; } } } \ No newline at end of file diff --git a/source/Server/Compilation/ICompiler.cs b/source/Server/Compilation/ICompiler.cs index 87a206f54..3a1409151 100644 --- a/source/Server/Compilation/ICompiler.cs +++ b/source/Server/Compilation/ICompiler.cs @@ -5,14 +5,13 @@ using Microsoft.CodeAnalysis; using MirrorSharp.Advanced; -namespace SharpLab.Server.Compilation { - public interface ICompiler { - Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( - MemoryStream assemblyStream, - MemoryStream? symbolStream, - IWorkSession session, - IList diagnostics, - CancellationToken cancellationToken - ); - } +namespace SharpLab.Server.Compilation; +public interface ICompiler { + Task<(bool assembly, bool symbols)> TryCompileToStreamAsync( + MemoryStream assemblyStream, + MemoryStream? symbolStream, + IWorkSession session, + IList diagnostics, + CancellationToken cancellationToken + ); } \ No newline at end of file diff --git a/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs b/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs index 30c7db597..44345e825 100644 --- a/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs +++ b/source/Server/Decompilation/AstOnly/FSharpAstTarget.cs @@ -14,335 +14,336 @@ using FSharp.Compiler.Syntax; using Range = FSharp.Compiler.Text.Range; -namespace SharpLab.Server.Decompilation.AstOnly { - public class FSharpAstTarget : IAstTarget { - private delegate void SerializeChildAction(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted, IFSharpSession session); - private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted, IFSharpSession session); - private delegate Range GetRangeFunc(object target); - - private static readonly string SyntaxNamespace = typeof(Ident).Namespace!; - private static readonly Lazy> TopLevelAstTypes = new( - () => typeof(Ident).Assembly.GetTypes().Where(t => t.Namespace == SyntaxNamespace && !t.IsNested).ToList(), - LazyThreadSafetyMode.ExecutionAndPublication - ); - - private static readonly ConcurrentDictionary> ChildrenSerializers = new(); - private static readonly ConcurrentDictionary> RangeGetters = new(); - private static readonly Lazy>> TagNameGetters = - new(SlowCompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication); - private static readonly Lazy>> ConstValueGetters = - new(SlowCompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication); - private static readonly Lazy> AstTypeNames = - new(SlowCollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication); - - private static class Methods { - // ReSharper disable MemberHidesStaticFromOuterClass - // ReSharper disable HeapView.DelegateAllocation - public static readonly MethodInfo SerializeNode = - ((SerializeChildAction)FSharpAstTarget.SerializeNode).Method.GetGenericMethodDefinition(); - public static readonly MethodInfo SerializeList = - ((SerializeChildAction>)FSharpAstTarget.SerializeList).Method.GetGenericMethodDefinition(); - public static readonly MethodInfo SerializeIdent = - ((SerializeChildAction)FSharpAstTarget.SerializeIdent).Method; - public static readonly MethodInfo SerializeIdentList = - ((SerializeChildAction>)FSharpAstTarget.SerializeIdentList).Method; - public static readonly MethodInfo SerializeEnum = - ((SerializeChildAction)FSharpAstTarget.SerializeEnum).Method.GetGenericMethodDefinition(); - // ReSharper restore HeapView.DelegateAllocation - // ReSharper restore MemberHidesStaticFromOuterClass - } +namespace SharpLab.Server.Decompilation.AstOnly; + +public class FSharpAstTarget : IAstTarget { + private delegate void SerializeChildAction(T item, IFastJsonWriter writer, string parentPropertyName, ref bool childrenStarted, IFSharpSession session); + private delegate void SerializeChildrenAction(object parent, IFastJsonWriter writer, ref bool childrenStarted, IFSharpSession session); + private delegate Range GetRangeFunc(object target); + + private static readonly string SyntaxNamespace = typeof(Ident).Namespace!; + private static readonly Lazy> TopLevelAstTypes = new( + () => typeof(Ident).Assembly.GetTypes().Where(t => t.Namespace == SyntaxNamespace && !t.IsNested).ToList(), + LazyThreadSafetyMode.ExecutionAndPublication + ); + + private static readonly ConcurrentDictionary> ChildrenSerializers = new(); + private static readonly ConcurrentDictionary> RangeGetters = new(); + private static readonly Lazy>> TagNameGetters = + new(SlowCompileTagNameGetters, LazyThreadSafetyMode.ExecutionAndPublication); + private static readonly Lazy>> ConstValueGetters = + new(SlowCompileConstValueGetters, LazyThreadSafetyMode.ExecutionAndPublication); + private static readonly Lazy> AstTypeNames = + new(SlowCollectAstTypeNames, LazyThreadSafetyMode.ExecutionAndPublication); + + private static class Methods { + // ReSharper disable MemberHidesStaticFromOuterClass + // ReSharper disable HeapView.DelegateAllocation + public static readonly MethodInfo SerializeNode = + ((SerializeChildAction)FSharpAstTarget.SerializeNode).Method.GetGenericMethodDefinition(); + public static readonly MethodInfo SerializeList = + ((SerializeChildAction>)FSharpAstTarget.SerializeList).Method.GetGenericMethodDefinition(); + public static readonly MethodInfo SerializeIdent = + ((SerializeChildAction)FSharpAstTarget.SerializeIdent).Method; + public static readonly MethodInfo SerializeIdentList = + ((SerializeChildAction>)FSharpAstTarget.SerializeIdentList).Method; + public static readonly MethodInfo SerializeEnum = + ((SerializeChildAction)FSharpAstTarget.SerializeEnum).Method.GetGenericMethodDefinition(); + // ReSharper restore HeapView.DelegateAllocation + // ReSharper restore MemberHidesStaticFromOuterClass + } - private static class EnumCache - where TEnum : struct, IFormattable { - public static readonly IReadOnlyDictionary Strings = Enum.GetValues(typeof(TEnum)).Cast().ToDictionary(e => e, e => e.ToString("G", null)); - } + private static class EnumCache + where TEnum : struct, IFormattable { + public static readonly IReadOnlyDictionary Strings = Enum.GetValues(typeof(TEnum)).Cast().ToDictionary(e => e, e => e.ToString("G", null)); + } - public Task GetAstAsync(IWorkSession session, CancellationToken cancellationToken) { - var parseResult = session.FSharp().GetLastParseResults(); - if (parseResult == null) - throw new InvalidOperationException("Current session does not include F# parse results yet."); - return Task.FromResult((object)parseResult.ParseTree); - } + public Task GetAstAsync(IWorkSession session, CancellationToken cancellationToken) { + var parseResult = session.FSharp().GetLastParseResults(); + if (parseResult == null) + throw new InvalidOperationException("Current session does not include F# parse results yet."); + return Task.FromResult((object)parseResult.ParseTree); + } - public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) { - var root = ((ParsedInput.ImplFile)ast).Item; - writer.WriteStartArray(); - var childrenStarted = true; - SerializeNode(root, writer, null, ref childrenStarted, session.FSharp()); - writer.WriteEndArray(); - } + public void SerializeAst(object ast, IFastJsonWriter writer, IWorkSession session) { + var root = ((ParsedInput.ImplFile)ast).Item; + writer.WriteStartArray(); + var childrenStarted = true; + SerializeNode(root, writer, null, ref childrenStarted, session.FSharp()); + writer.WriteEndArray(); + } - private static void SerializeNode(T node, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where T: notnull - { - EnsureChildrenStarted(ref parentChildrenStarted, writer); - writer.WriteStartObject(); - var nodeType = node.GetType(); - writer.WriteProperty("kind", AstTypeNames.Value[nodeType]); - if (parentPropertyName != null) - writer.WriteProperty("property", parentPropertyName); - - if (node is SynConst @const) { - writer.WriteProperty("type", "token"); - if (@const is SynConst.String @string) { - writer.WritePropertyName("value"); - writer.WriteValueFromParts("\"", @string.text, "\""); - } - else if (@const is SynConst.Char @char) { - writer.WritePropertyName("value"); - writer.WriteValueFromParts("'", @char.Item, "'"); - } - else { - if (ConstValueGetters.Value.TryGetValue(nodeType, out var getter)) { - writer.WritePropertyName("value"); - writer.WriteValue(getter(@const)); - } - } + private static void SerializeNode(T node, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where T: notnull + { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + writer.WriteStartObject(); + var nodeType = node.GetType(); + writer.WriteProperty("kind", AstTypeNames.Value[nodeType]); + if (parentPropertyName != null) + writer.WriteProperty("property", parentPropertyName); + + if (node is SynConst @const) { + writer.WriteProperty("type", "token"); + if (@const is SynConst.String @string) { + writer.WritePropertyName("value"); + writer.WriteValueFromParts("\"", @string.text, "\""); + } + else if (@const is SynConst.Char @char) { + writer.WritePropertyName("value"); + writer.WriteValueFromParts("'", @char.Item, "'"); } else { - writer.WriteProperty("type", nodeType.IsValueType ? "value" : "node"); - var tagName = GetTagName(node); - if (tagName != null) - writer.WriteProperty("value", tagName); + if (ConstValueGetters.Value.TryGetValue(nodeType, out var getter)) { + writer.WritePropertyName("value"); + writer.WriteValue(getter(@const)); + } } - var rangeGetter = GetRangeGetter(nodeType); - if (rangeGetter != null) - SerializeRangeProperty(rangeGetter(node), writer, session); + } + else { + writer.WriteProperty("type", nodeType.IsValueType ? "value" : "node"); + var tagName = GetTagName(node); + if (tagName != null) + writer.WriteProperty("value", tagName); + } + var rangeGetter = GetRangeGetter(nodeType); + if (rangeGetter != null) + SerializeRangeProperty(rangeGetter(node), writer, session); + + var childrenStarted = false; + GetChildrenSerializer(nodeType).Invoke(node, writer, ref childrenStarted, session); + EnsureChildrenEnded(childrenStarted, writer); + writer.WriteEndObject(); + } - var childrenStarted = false; - GetChildrenSerializer(nodeType).Invoke(node, writer, ref childrenStarted, session); - EnsureChildrenEnded(childrenStarted, writer); - writer.WriteEndObject(); + private static void SerializeList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where T: notnull + { + foreach (var item in list) { + SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted, session); } + } - private static void SerializeList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where T: notnull - { - foreach (var item in list) { - SerializeNode(item, writer, null /* UI does not support list property names at the moment */, ref parentChildrenStarted, session); - } + private static void SerializeIdent(Ident ident, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + writer.WriteStartObject(); + writer.WriteProperty("type", "token"); + writer.WriteProperty("kind", "Ident"); + if (parentPropertyName != null) + writer.WriteProperty("property", parentPropertyName); + writer.WriteProperty("value", ident.idText); + SerializeRangeProperty(ident.idRange, writer, session); + writer.WriteEndObject(); + } + + private static void SerializeIdentList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { + foreach (var ident in list) { + SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted, session); } + } - private static void SerializeIdent(Ident ident, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { - EnsureChildrenStarted(ref parentChildrenStarted, writer); + private static void SerializeEnum(TEnum value, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) + where TEnum : struct, IFormattable { + EnsureChildrenStarted(ref parentChildrenStarted, writer); + if (parentPropertyName != null) { writer.WriteStartObject(); - writer.WriteProperty("type", "token"); - writer.WriteProperty("kind", "Ident"); - if (parentPropertyName != null) - writer.WriteProperty("property", parentPropertyName); - writer.WriteProperty("value", ident.idText); - SerializeRangeProperty(ident.idRange, writer, session); + writer.WriteProperty("type", "value"); + writer.WriteProperty("property", parentPropertyName); + writer.WriteProperty("value", EnumCache.Strings[value]); writer.WriteEndObject(); } - - private static void SerializeIdentList(FSharpList list, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) { - foreach (var ident in list) { - SerializeIdent(ident, writer, parentPropertyName, ref parentChildrenStarted, session); - } + else { + writer.WriteValue(EnumCache.Strings[value]); } + } - private static void SerializeEnum(TEnum value, IFastJsonWriter writer, string? parentPropertyName, ref bool parentChildrenStarted, IFSharpSession session) - where TEnum : struct, IFormattable { - EnsureChildrenStarted(ref parentChildrenStarted, writer); - if (parentPropertyName != null) { - writer.WriteStartObject(); - writer.WriteProperty("type", "value"); - writer.WriteProperty("property", parentPropertyName); - writer.WriteProperty("value", EnumCache.Strings[value]); - writer.WriteEndObject(); - } - else { - writer.WriteValue(EnumCache.Strings[value]); - } - } + private static void SerializeRangeProperty(Range range, IFastJsonWriter writer, IFSharpSession session) { + writer.WritePropertyName("range"); + var startOffset = session.ConvertToOffset(range.StartLine, range.StartColumn); + var endOffset = session.ConvertToOffset(range.EndLine, range.EndColumn); + writer.WriteValueFromParts(startOffset, '-', endOffset); + } - private static void SerializeRangeProperty(Range range, IFastJsonWriter writer, IFSharpSession session) { - writer.WritePropertyName("range"); - var startOffset = session.ConvertToOffset(range.StartLine, range.StartColumn); - var endOffset = session.ConvertToOffset(range.EndLine, range.EndColumn); - writer.WriteValueFromParts(startOffset, '-', endOffset); - } + private static void EnsureChildrenStarted(ref bool childrenStarted, IFastJsonWriter writer) { + if (childrenStarted) + return; + writer.WritePropertyStartArray("children"); + childrenStarted = true; + } - private static void EnsureChildrenStarted(ref bool childrenStarted, IFastJsonWriter writer) { - if (childrenStarted) - return; - writer.WritePropertyStartArray("children"); - childrenStarted = true; - } + private static void EnsureChildrenEnded(bool childrenStarted, IFastJsonWriter writer) { + if (!childrenStarted) + return; + writer.WriteEndArray(); + } - private static void EnsureChildrenEnded(bool childrenStarted, IFastJsonWriter writer) { - if (!childrenStarted) - return; - writer.WriteEndArray(); + private static SerializeChildrenAction GetChildrenSerializer(Type type) { + if (!ChildrenSerializers.TryGetValue(type, out var lazySerialize)) { + lazySerialize = ChildrenSerializers.GetOrAdd( + type, + t => new(() => SlowCompileChildrenSerializer(t), LazyThreadSafetyMode.ExecutionAndPublication) + ); } - private static SerializeChildrenAction GetChildrenSerializer(Type type) { - if (!ChildrenSerializers.TryGetValue(type, out var lazySerialize)) { - lazySerialize = ChildrenSerializers.GetOrAdd( - type, - t => new(() => SlowCompileChildrenSerializer(t), LazyThreadSafetyMode.ExecutionAndPublication) - ); - } + return lazySerialize.Value; + } - return lazySerialize.Value; + private static SerializeChildrenAction SlowCompileChildrenSerializer(Type type) { + var nodeAsObject = Expression.Parameter(typeof(object)); + var writer = Expression.Parameter(typeof(IFastJsonWriter)); + var refChildrenStarted = Expression.Parameter(typeof(bool).MakeByRefType()); + var session = Expression.Parameter(typeof(IFSharpSession)); + + var node = Expression.Variable(type); + var body = new List { + Expression.Assign(node, Expression.Convert(nodeAsObject, type)) + }; + + foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { + if (ShouldSkipNodeProperty(type, property)) + continue; + var propertyType = property.PropertyType; + var method = SlowGetMethodToSerialize(propertyType); + if (method == null) + continue; + + var propertyName = property.Name; + if (Regex.IsMatch(propertyName, @"^Item\d*$")) + propertyName = null; + body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted, session)); } - private static SerializeChildrenAction SlowCompileChildrenSerializer(Type type) { - var nodeAsObject = Expression.Parameter(typeof(object)); - var writer = Expression.Parameter(typeof(IFastJsonWriter)); - var refChildrenStarted = Expression.Parameter(typeof(bool).MakeByRefType()); - var session = Expression.Parameter(typeof(IFSharpSession)); - - var node = Expression.Variable(type); - var body = new List { - Expression.Assign(node, Expression.Convert(nodeAsObject, type)) - }; + return Expression.Lambda( + Expression.Block(new[] { node }, body), + nodeAsObject, writer, refChildrenStarted, session + ).Compile(); + } - foreach (var property in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { - if (ShouldSkipNodeProperty(type, property)) - continue; - var propertyType = property.PropertyType; - var method = SlowGetMethodToSerialize(propertyType); - if (method == null) - continue; + private static MethodInfo? SlowGetMethodToSerialize(Type propertyType) { + if (propertyType == typeof(Ident)) + return Methods.SerializeIdent; - var propertyName = property.Name; - if (Regex.IsMatch(propertyName, @"^Item\d*$")) - propertyName = null; - body.Add(Expression.Call(method, Expression.Property(node, property), writer, Expression.Constant(propertyName, typeof(string)), refChildrenStarted, session)); - } + if (propertyType == typeof(FSharpList)) + return Methods.SerializeIdentList; - return Expression.Lambda( - Expression.Block(new[] { node }, body), - nodeAsObject, writer, refChildrenStarted, session - ).Compile(); + if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(FSharpList<>)) { + var elementType = propertyType.GetGenericArguments()[0]; + if (!IsNodeType(elementType)) + return null; + return Methods.SerializeList.MakeGenericMethod(elementType); } - private static MethodInfo? SlowGetMethodToSerialize(Type propertyType) { - if (propertyType == typeof(Ident)) - return Methods.SerializeIdent; - - if (propertyType == typeof(FSharpList)) - return Methods.SerializeIdentList; - - if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(FSharpList<>)) { - var elementType = propertyType.GetGenericArguments()[0]; - if (!IsNodeType(elementType)) - return null; - return Methods.SerializeList.MakeGenericMethod(elementType); - } - - if (!IsNodeType(propertyType)) - return null; + if (!IsNodeType(propertyType)) + return null; - if (propertyType.IsEnum) - return Methods.SerializeEnum.MakeGenericMethod(propertyType); + if (propertyType.IsEnum) + return Methods.SerializeEnum.MakeGenericMethod(propertyType); - return Methods.SerializeNode.MakeGenericMethod(propertyType); - } + return Methods.SerializeNode.MakeGenericMethod(propertyType); + } - private static GetRangeFunc? GetRangeGetter(Type type) { - return RangeGetters.GetOrAdd( - type, - t => new Lazy(() => CompileRangeGetter(t), LazyThreadSafetyMode.ExecutionAndPublication) - ).Value; - } + private static GetRangeFunc? GetRangeGetter(Type type) { + return RangeGetters.GetOrAdd( + type, + t => new Lazy(() => CompileRangeGetter(t), LazyThreadSafetyMode.ExecutionAndPublication) + ).Value; + } - private static GetRangeFunc? CompileRangeGetter(Type type) { - var rangeProperty = type.GetProperty("Range"); - if (rangeProperty == null) - return null; + private static GetRangeFunc? CompileRangeGetter(Type type) { + var rangeProperty = type.GetProperty("Range"); + if (rangeProperty == null) + return null; - var nodeAsObject = Expression.Parameter(typeof(object)); - var body = Expression.Property(Expression.Convert(nodeAsObject, type), rangeProperty); + var nodeAsObject = Expression.Parameter(typeof(object)); + var body = Expression.Property(Expression.Convert(nodeAsObject, type), rangeProperty); - return Expression.Lambda(body, new[] { nodeAsObject }).Compile(); - } + return Expression.Lambda(body, [nodeAsObject]).Compile(); + } - private static bool ShouldSkipNodeProperty(Type type, PropertyInfo property) { - return (type == typeof(LongIdentWithDots) && property.Name == nameof(LongIdentWithDots.id)); - } + private static bool ShouldSkipNodeProperty(Type type, PropertyInfo property) { + return false; + //return (type == typeof(LongIdentWithDots) && property.Name == nameof(LongIdentWithDots.id)); + } - private static bool IsNodeType(Type type) { - return type.Namespace == SyntaxNamespace - && type != typeof(QualifiedNameOfFile) - && type != typeof(SynModuleOrNamespaceKind) - && !(type.Name.StartsWith("SequencePoint")); - } + private static bool IsNodeType(Type type) { + return type.Namespace == SyntaxNamespace + && type != typeof(QualifiedNameOfFile) + && type != typeof(SynModuleOrNamespaceKind) + && !(type.Name.StartsWith("SequencePoint")); + } - private static string? GetTagName(object node) { - return TagNameGetters.Value.TryGetValue(node.GetType(), out var getter) - ? getter.Invoke(node) - : null; - } + private static string? GetTagName(object node) { + return TagNameGetters.Value.TryGetValue(node.GetType(), out var getter) + ? getter.Invoke(node) + : null; + } - private static IReadOnlyDictionary> SlowCompileTagNameGetters() { - var getters = new Dictionary>(); - void SlowCompileAndCollectRecursive(Type astType) { - foreach (var nested in astType.GetNestedTypes()) { - if (nested.Name == "Tags") { - getters.Add(astType, SlowCompileTagNameGetter(astType, nested)); - continue; - } - SlowCompileAndCollectRecursive(nested); + private static IReadOnlyDictionary> SlowCompileTagNameGetters() { + var getters = new Dictionary>(); + void SlowCompileAndCollectRecursive(Type astType) { + foreach (var nested in astType.GetNestedTypes()) { + if (nested.Name == "Tags") { + getters.Add(astType, SlowCompileTagNameGetter(astType, nested)); + continue; } + SlowCompileAndCollectRecursive(nested); } - - foreach (var topLevel in TopLevelAstTypes.Value) { - SlowCompileAndCollectRecursive(topLevel); - } - return getters; } - private static Func SlowCompileTagNameGetter(Type astType, Type tagsType) { - var tagMap = tagsType - .GetFields() - .OrderBy(f => (int)f.GetValue(null)!) - .Select(f => f.Name) - .ToArray(); - var nodeUntyped = Expression.Parameter(typeof(object)); - var tagGetter = Expression.Lambda>( - Expression.Property(Expression.Convert(nodeUntyped, astType), "Tag"), - nodeUntyped - ).Compile(); - return instance => tagMap[tagGetter(instance)]; + foreach (var topLevel in TopLevelAstTypes.Value) { + SlowCompileAndCollectRecursive(topLevel); } + return getters; + } - private static IReadOnlyDictionary> SlowCompileConstValueGetters() { - var getters = new Dictionary>(); - foreach (var type in typeof(SynConst).GetNestedTypes()) { - if (type.BaseType != typeof(SynConst)) - continue; - - var valueProperty = type.GetProperty("Item"); - if (valueProperty == null) - continue; + private static Func SlowCompileTagNameGetter(Type astType, Type tagsType) { + var tagMap = tagsType + .GetFields() + .OrderBy(f => (int)f.GetValue(null)!) + .Select(f => f.Name) + .ToArray(); + var nodeUntyped = Expression.Parameter(typeof(object)); + var tagGetter = Expression.Lambda>( + Expression.Property(Expression.Convert(nodeUntyped, astType), "Tag"), + nodeUntyped + ).Compile(); + return instance => tagMap[tagGetter(instance)]; + } - var toString = valueProperty.PropertyType.GetMethod("ToString", Type.EmptyTypes)!; - var constUntyped = Expression.Parameter(typeof(SynConst)); - getters.Add(type, Expression.Lambda>( - Expression.Call(Expression.Property(Expression.Convert(constUntyped, type), valueProperty), toString), - constUntyped - ).Compile()); - } - return getters; + private static IReadOnlyDictionary> SlowCompileConstValueGetters() { + var getters = new Dictionary>(); + foreach (var type in typeof(SynConst).GetNestedTypes()) { + if (type.BaseType != typeof(SynConst)) + continue; + + var valueProperty = type.GetProperty("Item"); + if (valueProperty == null) + continue; + + var toString = valueProperty.PropertyType.GetMethod("ToString", Type.EmptyTypes)!; + var constUntyped = Expression.Parameter(typeof(SynConst)); + getters.Add(type, Expression.Lambda>( + Expression.Call(Expression.Property(Expression.Convert(constUntyped, type), valueProperty), toString), + constUntyped + ).Compile()); } + return getters; + } - private static IReadOnlyDictionary SlowCollectAstTypeNames() { - var results = new Dictionary(); - void CollectRecusive(IEnumerable astTypes, string parentPrefix) { - foreach (var astType in astTypes) { - var name = parentPrefix + astType.Name; - var prefix = name + "."; - results.Add(astType, name); - CollectRecusive(astType.GetNestedTypes(), prefix); - } + private static IReadOnlyDictionary SlowCollectAstTypeNames() { + var results = new Dictionary(); + void CollectRecusive(IEnumerable astTypes, string parentPrefix) { + foreach (var astType in astTypes) { + var name = parentPrefix + astType.Name; + var prefix = name + "."; + results.Add(astType, name); + CollectRecusive(astType.GetNestedTypes(), prefix); } - - CollectRecusive(TopLevelAstTypes.Value, ""); - return results; } - public IReadOnlyCollection SupportedLanguageNames { get; } = new[] { "F#" }; + CollectRecusive(TopLevelAstTypes.Value, ""); + return results; } + + public IReadOnlyCollection SupportedLanguageNames { get; } = new[] { "F#" }; } \ No newline at end of file diff --git a/source/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs b/source/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs index ec84493c6..09ea1aed4 100644 --- a/source/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs +++ b/source/Server/Decompilation/AstOnly/Internal/RoslynOperationPropertySerializer.cs @@ -115,7 +115,10 @@ private bool SlowShouldSkip(PropertyInfo property) { return property.Name == nameof(IOperation.Language) || property.Name == nameof(IOperation.Kind) || property.Name == nameof(IOperation.Parent) + #pragma warning disable CS0618 // Type or member is obsolete || property.Name == nameof(IOperation.Children) + #pragma warning restore CS0618 // Type or member is obsolete + || property.Name == nameof(IOperation.ChildOperations) || property.Name == nameof(IOperation.Syntax) || property.PropertyType.IsAssignableTo() || property.PropertyType.IsAssignableTo>(); diff --git a/source/Server/Decompilation/CSharpDecompiler.cs b/source/Server/Decompilation/CSharpDecompiler.cs index cb5b8051f..3934ea943 100644 --- a/source/Server/Decompilation/CSharpDecompiler.cs +++ b/source/Server/Decompilation/CSharpDecompiler.cs @@ -1,63 +1,132 @@ using System; using System.IO; +using System.Runtime.CompilerServices; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp.OutputVisitor; +using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.Metadata; +using MirrorSharp.Advanced; using SharpLab.Server.Common; using SharpLab.Server.Decompilation.Internal; -namespace SharpLab.Server.Decompilation { - public class CSharpDecompiler : IDecompiler { - private static readonly CSharpFormattingOptions FormattingOptions = CreateFormattingOptions(); - private static readonly DecompilerSettings DecompilerSettings = new(ICSharpCode.Decompiler.CSharp.LanguageVersion.CSharp1) { - ArrayInitializers = false, - AutomaticEvents = false, - DecimalConstants = false, - FixedBuffers = false, - UsingStatement = false, - SwitchStatementOnString = false, - LockStatement = false, - ForStatement = false, - ForEachStatement = false, - SparseIntegerSwitch = false, - DoWhileStatement = false, - StringConcat = false, - UseRefLocalsForAccurateOrderOfEvaluation = true, - InitAccessors = true, - FunctionPointers = true, - NativeIntegers = true +namespace SharpLab.Server.Decompilation; + +public class CSharpDecompiler : IDecompiler { + private static readonly CSharpFormattingOptions FormattingOptions = CreateFormattingOptions(); + private static readonly DecompilerSettings DecompilerSettings = new(ICSharpCode.Decompiler.CSharp.LanguageVersion.CSharp1) { + ArrayInitializers = false, + AutomaticEvents = false, + DecimalConstants = false, + FixedBuffers = false, + UsingStatement = false, + SwitchStatementOnString = false, + LockStatement = false, + ForStatement = false, + ForEachStatement = false, + SparseIntegerSwitch = false, + DoWhileStatement = false, + StringConcat = false, + UseRefLocalsForAccurateOrderOfEvaluation = true, + InitAccessors = true, + FunctionPointers = true, + NativeIntegers = true + }; + + private readonly IAssemblyResolver _assemblyResolver; + private readonly Func _debugInfoFactory; + + public CSharpDecompiler(IAssemblyResolver assemblyResolver, Func debugInfoFactory) { + _assemblyResolver = assemblyResolver; + _debugInfoFactory = debugInfoFactory; + } + + public void Decompile(CompilationStreamPair streams, TextWriter codeWriter, IWorkSession session) { + Argument.NotNull(nameof(streams), streams); + Argument.NotNull(nameof(codeWriter), codeWriter); + Argument.NotNull(nameof(session), session); + + using var assemblyFile = new PEFile("", streams.AssemblyStream); + using var debugInfo = streams.SymbolStream != null ? _debugInfoFactory(streams.SymbolStream) : null; + + var decompiler = new ICSharpCode.Decompiler.CSharp.CSharpDecompiler(assemblyFile, _assemblyResolver, DecompilerSettings) { + DebugInfoProvider = debugInfo }; + var syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(); + + SortTree(syntaxTree); + + new ExtendedCSharpOutputVisitor(codeWriter, FormattingOptions) + .VisitSyntaxTree(syntaxTree); + } - private readonly IAssemblyResolver _assemblyResolver; - private readonly Func _debugInfoFactory; + private void SortTree(SyntaxTree root) { + // Note: the sorting logic cannot be reused, but should match IL and Jit ASM ordering + var firstMovedNode = (AstNode?)null; + foreach (var node in root.Children) { + if (node == firstMovedNode) + break; - public CSharpDecompiler(IAssemblyResolver assemblyResolver, Func debugInfoFactory) { - _assemblyResolver = assemblyResolver; - _debugInfoFactory = debugInfoFactory; + if (node is NamespaceDeclaration @namespace && IsNonUserCode(@namespace)) { + node.Remove(); + root.AddChildWithExistingRole(node); + firstMovedNode ??= node; + } } + } - public void Decompile(CompilationStreamPair streams, TextWriter codeWriter) { - Argument.NotNull(nameof(streams), streams); - Argument.NotNull(nameof(codeWriter), codeWriter); + private bool IsNonUserCode(NamespaceDeclaration @namespace) { + // Note: the logic cannot be reused, but should match IL and Jit ASM + foreach (var member in @namespace.Members) { + if (member is not TypeDeclaration type) + return false; - using (var assemblyFile = new PEFile("", streams.AssemblyStream)) - using (var debugInfo = streams.SymbolStream != null ? _debugInfoFactory(streams.SymbolStream) : null) { - var decompiler = new ICSharpCode.Decompiler.CSharp.CSharpDecompiler(assemblyFile, _assemblyResolver, DecompilerSettings) { - DebugInfoProvider = debugInfo - }; - var syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(); + if (!IsCompilerGenerated(type)) + return false; + } + + return true; + } - new CSharpOutputVisitor(codeWriter, FormattingOptions).VisitSyntaxTree(syntaxTree); + private bool IsCompilerGenerated(TypeDeclaration type) { + foreach (var section in type.Attributes) { + foreach (var attribute in section.Attributes) { + if (attribute.Type is SimpleType { Identifier: nameof(CompilerGeneratedAttribute) or "CompilerGenerated" }) + return true; } } + return false; + } + + public string LanguageName => TargetNames.CSharp; + + private static CSharpFormattingOptions CreateFormattingOptions() + { + var options = FormattingOptionsFactory.CreateAllman(); + options.IndentationString = " "; + options.MinimumBlankLinesBetweenTypes = 1; + return options; + } + + private class ExtendedCSharpOutputVisitor : CSharpOutputVisitor { + public ExtendedCSharpOutputVisitor(TextWriter textWriter, CSharpFormattingOptions formattingPolicy) : base(textWriter, formattingPolicy) { + } - public string LanguageName => TargetNames.CSharp; + public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration) { + base.VisitTypeDeclaration(typeDeclaration); + if (typeDeclaration.NextSibling is NamespaceDeclaration or TypeDeclaration) + NewLine(); + } + + public override void VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) { + base.VisitNamespaceDeclaration(namespaceDeclaration); + if (namespaceDeclaration.NextSibling is NamespaceDeclaration or TypeDeclaration) + NewLine(); + } - private static CSharpFormattingOptions CreateFormattingOptions() - { - var options = FormattingOptionsFactory.CreateAllman(); - options.IndentationString = " "; - return options; + public override void VisitAttributeSection(AttributeSection attributeSection) { + base.VisitAttributeSection(attributeSection); + if (attributeSection is { AttributeTarget: "assembly" or "module", NextSibling: not AttributeSection { AttributeTarget: "assembly" or "module" } }) + NewLine(); } } } \ No newline at end of file diff --git a/source/Server/Decompilation/DecompilationModule.cs b/source/Server/Decompilation/DecompilationModule.cs index 949ef7572..b65060e07 100644 --- a/source/Server/Decompilation/DecompilationModule.cs +++ b/source/Server/Decompilation/DecompilationModule.cs @@ -1,6 +1,8 @@ using System; +using System.Reflection.Metadata; using Autofac; using JetBrains.Annotations; +using SharpLab.Server.Common; using SharpLab.Server.Decompilation.AstOnly; using SharpLab.Server.Decompilation.Internal; @@ -8,6 +10,8 @@ namespace SharpLab.Server.Decompilation { [UsedImplicitly] public class DecompilationModule : Module { protected override void Load(ContainerBuilder builder) { + builder.RegisterInstance(MemoryPoolSlim.Shared); + builder.RegisterType() .As() .SingleInstance(); @@ -26,6 +30,10 @@ protected override void Load(ContainerBuilder builder) { .As() .SingleInstance(); builder.RegisterType() + .As() + .As() + .SingleInstance(); + builder.RegisterType() .As() .SingleInstance(); diff --git a/source/Server/Decompilation/ExecutionILDecompiler.cs b/source/Server/Decompilation/ExecutionILDecompiler.cs new file mode 100644 index 000000000..fa15ecc3e --- /dev/null +++ b/source/Server/Decompilation/ExecutionILDecompiler.cs @@ -0,0 +1,27 @@ +using System.IO; +using MirrorSharp.Advanced; +using SharpLab.Server.Common; +using SharpLab.Server.Decompilation.Internal; +using SharpLab.Server.Execution.Internal; + +namespace SharpLab.Server.Decompilation { + public class ExecutionILDecompiler : IDecompiler { + private readonly IAssemblyStreamRewriterComposer _rewriter; + private readonly IILDecompiler _ilDecompiler; + + public ExecutionILDecompiler(IAssemblyStreamRewriterComposer rewriter, IILDecompiler ilDecompiler) { + _rewriter = rewriter; + _ilDecompiler = ilDecompiler; + } + + public void Decompile(CompilationStreamPair streams, TextWriter codeWriter, IWorkSession session) { + Argument.NotNull(nameof(streams), streams); + Argument.NotNull(nameof(codeWriter), codeWriter); + + using var rewritten = _rewriter.Rewrite(streams, session); + _ilDecompiler.Decompile(rewritten.Stream, symbolStream: null, codeWriter); + } + + public string LanguageName => TargetNames.RunIL; + } +} \ No newline at end of file diff --git a/source/Server/Decompilation/IDecompiler.cs b/source/Server/Decompilation/IDecompiler.cs index 40f8937c7..a98d4496d 100644 --- a/source/Server/Decompilation/IDecompiler.cs +++ b/source/Server/Decompilation/IDecompiler.cs @@ -1,10 +1,10 @@ using System.IO; -using JetBrains.Annotations; +using MirrorSharp.Advanced; using SharpLab.Server.Common; namespace SharpLab.Server.Decompilation { public interface IDecompiler { - [NotNull] string LanguageName { get; } - void Decompile([NotNull] CompilationStreamPair streams, [NotNull] TextWriter codeWriter); + string LanguageName { get; } + void Decompile(CompilationStreamPair streams, TextWriter codeWriter, IWorkSession session); } } \ No newline at end of file diff --git a/source/Server/Decompilation/ILDecompiler.cs b/source/Server/Decompilation/ILDecompiler.cs index 8e34dcdf7..73d8a7d3e 100644 --- a/source/Server/Decompilation/ILDecompiler.cs +++ b/source/Server/Decompilation/ILDecompiler.cs @@ -1,42 +1,101 @@ using System; using System.IO; +using System.Reflection.Metadata; using System.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Metadata; -using Mono.Cecil.Cil; +using MirrorSharp.Advanced; using SharpLab.Server.Common; -using SharpLab.Server.Common.Diagnostics; using SharpLab.Server.Decompilation.Internal; namespace SharpLab.Server.Decompilation { - public class ILDecompiler : IDecompiler { - private readonly ISymbolReaderProvider _symbolReaderProvider; + public class ILDecompiler : IILDecompiler { private readonly Func _debugInfoFactory; + private readonly MemoryPoolSlim _typeHandleMemoryPool; - public ILDecompiler(ISymbolReaderProvider symbolReaderProvider, Func debugInfoFactory) { - _symbolReaderProvider = symbolReaderProvider; + public ILDecompiler( + Func debugInfoFactory, + MemoryPoolSlim typeHandleMemoryPool + ) { _debugInfoFactory = debugInfoFactory; + _typeHandleMemoryPool = typeHandleMemoryPool; } - public void Decompile(CompilationStreamPair streams, TextWriter codeWriter) { + public void Decompile(CompilationStreamPair streams, TextWriter codeWriter, IWorkSession session) { Argument.NotNull(nameof(streams), streams); Argument.NotNull(nameof(codeWriter), codeWriter); + Argument.NotNull(nameof(session), session); - using (var assemblyFile = new PEFile("_", streams.AssemblyStream)) - using (var debugInfo = streams.SymbolStream != null ? _debugInfoFactory(streams.SymbolStream) : null) { - var output = new PlainTextOutput(codeWriter) { IndentationString = " " }; - var disassembler = new ReflectionDisassembler(output, CancellationToken.None) { - DebugInfo = debugInfo, - ShowSequencePoints = true - }; - - disassembler.WriteAssemblyHeader(assemblyFile); - output.WriteLine(); // empty line - disassembler.WriteModuleContents(assemblyFile); + Decompile(streams.AssemblyStream, streams.SymbolStream, codeWriter); + } + + public void Decompile(Stream assemblyStream, Stream? symbolStream, TextWriter codeWriter) { + Argument.NotNull(nameof(assemblyStream), assemblyStream); + Argument.NotNull(nameof(codeWriter), codeWriter); + + using var assemblyFile = new PEFile("_", assemblyStream); + using var debugInfo = symbolStream != null ? _debugInfoFactory(symbolStream) : null; + + var output = new PlainTextOutput(codeWriter) { IndentationString = " " }; + var disassembler = new ReflectionDisassembler(output, CancellationToken.None) { + DebugInfo = debugInfo, + ShowSequencePoints = true + }; + + disassembler.WriteAssemblyHeader(assemblyFile); + output.WriteLine(); // empty line + + var metadata = assemblyFile.Metadata; + DecompileTypes(assemblyFile, output, disassembler, metadata); + } + + private void DecompileTypes(PEFile assemblyFile, PlainTextOutput output, ReflectionDisassembler disassembler, MetadataReader metadata) { + const int MaxNonUserTypeHandles = 10; + var nonUserTypeHandlesLease = default(MemoryLease); + var nonUserTypeHandlesCount = -1; + + try { + // user code (first) + foreach (var typeHandle in metadata.TypeDefinitions) { + var type = metadata.GetTypeDefinition(typeHandle); + if (!type.GetDeclaringType().IsNil) + continue; // not a top-level type + + if (IsNonUserCode(metadata, type) && nonUserTypeHandlesCount < MaxNonUserTypeHandles) { + if (nonUserTypeHandlesCount == -1) { + nonUserTypeHandlesLease = _typeHandleMemoryPool.RentExact(25); + nonUserTypeHandlesCount = 0; + } + + nonUserTypeHandlesLease.AsSpan()[nonUserTypeHandlesCount] = typeHandle; + nonUserTypeHandlesCount += 1; + continue; + } + + disassembler.DisassembleType(assemblyFile, typeHandle); + output.WriteLine(); + } + + // non-user code (second) + if (nonUserTypeHandlesCount > 0) { + foreach (var typeHandle in nonUserTypeHandlesLease.AsSpan().Slice(0, nonUserTypeHandlesCount)) { + disassembler.DisassembleType(assemblyFile, typeHandle); + output.WriteLine(); + } + } + } + finally { + nonUserTypeHandlesLease.Dispose(); } } + private bool IsNonUserCode(MetadataReader metadata, TypeDefinition type) { + // Note: the logic cannot be reused, but should match C# and Jit ASM + return !type.NamespaceDefinition.IsNil + && type.IsCompilerGenerated(metadata); + } + public string LanguageName => TargetNames.IL; } } \ No newline at end of file diff --git a/source/Server/Decompilation/Internal/IILDecompiler.cs b/source/Server/Decompilation/Internal/IILDecompiler.cs new file mode 100644 index 000000000..17edf23d7 --- /dev/null +++ b/source/Server/Decompilation/Internal/IILDecompiler.cs @@ -0,0 +1,7 @@ +using System.IO; + +namespace SharpLab.Server.Decompilation.Internal { + public interface IILDecompiler : IDecompiler { + void Decompile(Stream assemblyStream, Stream? symbolStream, TextWriter codeWriter); + } +} diff --git a/source/Server/Decompilation/JitAsmDecompiler.cs b/source/Server/Decompilation/JitAsmDecompiler.cs index 4461918d3..04826f322 100644 --- a/source/Server/Decompilation/JitAsmDecompiler.cs +++ b/source/Server/Decompilation/JitAsmDecompiler.cs @@ -4,346 +4,381 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using AshMind.Extensions; using Iced.Intel; using JetBrains.Annotations; using Microsoft.Diagnostics.Runtime; -using Microsoft.Diagnostics.Runtime.DacInterface; +using MirrorSharp.Advanced; using SharpLab.Runtime; using SharpLab.Runtime.Internal; using SharpLab.Server.Common; +using SharpLab.Server.Common.Diagnostics; using SharpLab.Server.Decompilation.Internal; -namespace SharpLab.Server.Decompilation { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class JitAsmDecompiler : IDecompiler { - private static readonly FormatterOptions FormatterOptions = new() { - HexPrefix = "0x", - HexSuffix = null, - UppercaseHex = false, - SpaceAfterOperandSeparator = true - }; - private readonly Pool _runtimePool; - private readonly JitAsmSettings _settings; +namespace SharpLab.Server.Decompilation; - public string LanguageName => TargetNames.JitAsm; +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class JitAsmDecompiler : IDecompiler { + private static readonly FormatterOptions FormatterOptions = new() { + HexPrefix = "0x", + HexSuffix = null, + UppercaseHex = false, + SpaceAfterOperandSeparator = true + }; + private readonly Pool _runtimePool; + private readonly JitAsmSettings _settings; - public JitAsmDecompiler(Pool runtimePool, JitAsmSettings settings) { - _runtimePool = runtimePool; - _settings = settings; - } + public string LanguageName => TargetNames.JitAsm; - public void Decompile(CompilationStreamPair streams, TextWriter codeWriter) { - Argument.NotNull(nameof(streams), streams); - Argument.NotNull(nameof(codeWriter), codeWriter); + public JitAsmDecompiler(Pool runtimePool, JitAsmSettings settings) { + _runtimePool = runtimePool; + _settings = settings; + } - using var loadContext = new CustomAssemblyLoadContext(shouldShareAssembly: _ => true); - var assembly = loadContext.LoadFromStream(streams.AssemblyStream); - ValidateStaticConstructors(assembly); + public void Decompile(CompilationStreamPair streams, TextWriter codeWriter, IWorkSession session) { + Argument.NotNull(nameof(streams), streams); + Argument.NotNull(nameof(codeWriter), codeWriter); + Argument.NotNull(nameof(session), session); - using var runtimeLease = _runtimePool.GetOrCreate(); - var runtime = runtimeLease.Object; + using var loadContext = new CustomAssemblyLoadContext(shouldShareAssembly: _ => true); + var assembly = loadContext.LoadFromStream(streams.AssemblyStream); + EnsureNoJitSideEffects(assembly); - runtime.FlushCachedData(); - var context = new JitWriteContext(codeWriter, runtime); + using var runtimeLease = _runtimePool.GetOrCreate(); + var runtime = runtimeLease.Object; - WriteJitInfo(runtime.ClrInfo, codeWriter); - WriteProfilerState(codeWriter); + runtime.FlushCachedData(); + var context = new JitWriteContext(codeWriter, runtime); + + WriteJitInfo(runtime.ClrInfo, codeWriter); + WriteProfilerState(codeWriter); + + DisassembleAndWriteTypesInOrder(context, assembly); + } + private void EnsureNoJitSideEffects(Assembly assembly) { + try { foreach (var type in assembly.DefinedTypes) { - if (type.IsNested) - continue; // it's easier to handle nested generic types recursively, so we suppress all nested for consistency - DisassembleAndWriteMembers(context, type); - } - } + foreach (var constructor in type.DeclaredConstructors) { + if (constructor.IsStatic) + throw new NotSupportedException($"Type {type} has a static constructor, which is not supported by SharpLab JIT decompiler."); + } - private void ValidateStaticConstructors(Assembly assembly) { - try { - foreach (var type in assembly.DefinedTypes) { - foreach (var constructor in type.DeclaredConstructors) { - if (constructor.IsStatic) - throw new NotSupportedException($"Type {type} has a static constructor, which is not supported by SharpLab JIT decompiler."); + foreach (var method in type.DeclaredMethods) { + foreach (var attribute in method.CustomAttributes) { + if (attribute.AttributeType is { Name: "ModuleInitializerAttribute", Namespace: "System.Runtime.CompilerServices" }) + throw new NotSupportedException($"Method {method} is a module initializer, which is not supported by SharpLab JIT decompiler."); } } } - catch (ReflectionTypeLoadException ex) { - throw new NotSupportedException("Unable to validate whether code is using static contructors (not supported by SharpLab JIT decompiler).", ex); - } - } - - private void WriteJitInfo(ClrInfo clr, TextWriter writer) { - writer.WriteLine( - "; {0:G} CLR {1} on {2}", - clr.Flavor, clr.Version, clr.DacInfo.TargetArchitecture.ToString("G").ToLowerInvariant() - ); } - - private void WriteProfilerState(TextWriter writer) { - if (!ProfilerState.Active) - return; - - writer.WriteLine("; Note: Running under profiler, which affects JIT assembly in heap allocations."); + catch (ReflectionTypeLoadException ex) { + throw new NotSupportedException("Unable to validate whether code has static constructors or module initializers (not supported by SharpLab JIT decompiler).", ex); } + } - private void DisassembleAndWriteMembers(JitWriteContext context, TypeInfo type, ImmutableArray? genericArgumentTypes = null) { - if (type.IsGenericTypeDefinition) { - if (TryDisassembleAndWriteMembersOfGeneric(context, type, genericArgumentTypes)) - return; - } - - foreach (var constructor in type.DeclaredConstructors) { - DisassembleAndWriteMethod(context, constructor); - } + private void WriteJitInfo(ClrInfo clr, TextWriter writer) { + writer.WriteLine( + "; {0:G} CLR {1} on {2}", + clr.Flavor, clr.Version, clr.DataTarget.DataReader.Architecture.ToString("G").ToLowerInvariant() + ); + } - foreach (var method in type.DeclaredMethods) { - if (method.IsAbstract) - continue; - DisassembleAndWriteMethod(context, method); - } + private void WriteProfilerState(TextWriter writer) { + if (!ProfilerState.Active) + return; - foreach (var nested in type.DeclaredNestedTypes) { - DisassembleAndWriteMembers(context, nested, genericArgumentTypes); - } - } + writer.WriteLine("; Note: Running under profiler, which affects JIT assembly in heap allocations."); + } - private bool TryDisassembleAndWriteMembersOfGeneric(JitWriteContext context, TypeInfo type, ImmutableArray? parentArgumentTypes = null) { - var hadAttribute = false; - foreach (var attribute in type.GetCustomAttributes(false)) { - hadAttribute = true; + private void DisassembleAndWriteTypesInOrder(JitWriteContext context, Assembly assembly) { + var lastNonUserTypeIndex = -1; + var types = assembly.GetTypes(); + for (var i = 0; i < types.Length; i++) { + var type = types[i]; - var fullArgumentTypes = (parentArgumentTypes ?? ImmutableArray.Empty) - .AddRange(attribute.ArgumentTypes); - var genericInstance = ApplyJitGenericAttribute(type, fullArgumentTypes.ToArray(), static (t, a) => t.MakeGenericType(a)); - DisassembleAndWriteMembers(context, genericInstance.GetTypeInfo(), fullArgumentTypes); - } - if (hadAttribute) - return true; + if (type.IsNested) + continue; // it's easier to handle nested generic types recursively, so we suppress all nested for consistency - if (parentArgumentTypes != null) { - var genericInstance = ApplyJitGenericAttribute(type, parentArgumentTypes.Value.ToArray(), static (t, a) => t.MakeGenericType(a)); - DisassembleAndWriteMembers(context, genericInstance.GetTypeInfo(), parentArgumentTypes); - return true; + if (IsNonUserCode(type)) { + lastNonUserTypeIndex = i; + continue; } - return false; + DisassembleAndWriteMembers(context, type.GetTypeInfo()); } - private void DisassembleAndWriteMethod(JitWriteContext context, MethodBase method) { - if ((method.MethodImplementationFlags & MethodImplAttributes.Runtime) == MethodImplAttributes.Runtime) { - WriteSignatureFromReflection(context, method); - context.Writer.WriteLine(" ; Cannot produce JIT assembly for runtime-implemented method."); - return; - } - - if ((method.Attributes & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl) { - WriteSignatureFromReflection(context, method); - context.Writer.WriteLine(" ; Cannot produce JIT assembly for a P/Invoke method."); - return; + if (lastNonUserTypeIndex >= 0) { + for (var i = 0; i <= lastNonUserTypeIndex; i++) { + DisassembleAndWriteMembers(context, types[i].GetTypeInfo()); } + } + } - if (method.DeclaringType?.IsGenericTypeDefinition ?? false) { - WriteIgnoredOpenGeneric(context, method); - return; - } + private bool IsNonUserCode(Type type) { + // Note: the logic cannot be reused, but should match C# and IL + return type.Namespace != null + && type.IsDefined(); + } - if (method.IsGenericMethodDefinition) { - DisassembleAndWriteGenericMethod(context, (MethodInfo)method); + private void DisassembleAndWriteMembers(JitWriteContext context, TypeInfo type, ImmutableArray? genericArgumentTypes = null) { + if (type.IsGenericTypeDefinition) { + if (TryDisassembleAndWriteMembersOfGeneric(context, type, genericArgumentTypes)) return; - } + } - DisassembleAndWriteSimpleMethod(context, method); + foreach (var constructor in type.DeclaredConstructors) { + DisassembleAndWriteMethod(context, constructor); } - private void DisassembleAndWriteGenericMethod(JitWriteContext context, MethodInfo method) { - var hasAttribute = false; - foreach (var attribute in method.GetCustomAttributes()) { - hasAttribute = true; - var genericInstance = ApplyJitGenericAttribute(method, attribute.ArgumentTypes, static (m, a) => m.MakeGenericMethod(a)); - DisassembleAndWriteSimpleMethod(context, genericInstance); - } - if (!hasAttribute) - WriteIgnoredOpenGeneric(context, method); + foreach (var method in type.DeclaredMethods) { + if (method.IsAbstract) + continue; + DisassembleAndWriteMethod(context, method); } - private void DisassembleAndWriteSimpleMethod(JitWriteContext context, MethodBase method) { - var handle = method.MethodHandle; - RuntimeHelpers.PrepareMethod(handle); + foreach (var nested in type.DeclaredNestedTypes) { + DisassembleAndWriteMembers(context, nested, genericArgumentTypes); + } + } - var clrMethodData = FindJitCompiledMethod(context, handle); + private bool TryDisassembleAndWriteMembersOfGeneric(JitWriteContext context, TypeInfo type, ImmutableArray? parentArgumentTypes = null) { + var hadAttribute = false; + foreach (var attribute in type.GetCustomAttributes(false)) { + hadAttribute = true; - var writer = context.Writer; - if (clrMethodData?.Signature is {} signature) { - writer.WriteLine(); - writer.WriteLine(signature); - } - else { - WriteSignatureFromReflection(context, method); - } + var fullArgumentTypes = (parentArgumentTypes ?? []) + .AddRange(attribute.ArgumentTypes); + var genericInstance = ApplyJitGenericAttribute(type, fullArgumentTypes.ToArray(), static (t, a) => t.MakeGenericType(a)); + DisassembleAndWriteMembers(context, genericInstance.GetTypeInfo(), fullArgumentTypes); + } + if (hadAttribute) + return true; - if (clrMethodData == null) { - if (method.IsGenericMethod) { - writer.WriteLine(" ; Failed to find JIT output for generic method (reference types?)."); - writer.WriteLine(" ; If you know a solution, please comment at https://github.com/ashmind/SharpLab/issues/99."); - return; - } + if (parentArgumentTypes != null) { + var genericInstance = ApplyJitGenericAttribute(type, parentArgumentTypes.Value.ToArray(), static (t, a) => t.MakeGenericType(a)); + DisassembleAndWriteMembers(context, genericInstance.GetTypeInfo(), parentArgumentTypes); + return true; + } - writer.WriteLine(" ; Failed to find JIT output — please report at https://github.com/ashmind/SharpLab/issues."); - return; - } + return false; + } - var methodAddress = clrMethodData.Value.MethodAddress; - var methodLength = clrMethodData.Value.MethodSize; + private void DisassembleAndWriteMethod(JitWriteContext context, MethodBase method) { + #if DEBUG + DiagnosticLog.LogMessage($"[JitAsm] Processing method {method.Name}"); + #endif - var reader = new MemoryCodeReader(new IntPtr(unchecked((long)methodAddress)), methodLength); - var decoder = Decoder.Create(MapArchitectureToBitness(context.Runtime.DataTarget!.DataReader.Architecture), reader); + if ((method.MethodImplementationFlags & MethodImplAttributes.Runtime) == MethodImplAttributes.Runtime) { + WriteSignatureFromReflection(context, method); + context.Writer.WriteLine(" ; Cannot produce JIT assembly for runtime-implemented method."); + return; + } - var instructions = new InstructionList(); - decoder.IP = methodAddress; - while (decoder.IP < (methodAddress + methodLength)) { - decoder.Decode(out instructions.AllocUninitializedElement()); - } + if ((method.MethodImplementationFlags & MethodImplAttributes.InternalCall) == MethodImplAttributes.InternalCall) { + WriteSignatureFromReflection(context, method); + context.Writer.WriteLine(" ; Cannot produce JIT assembly for an internal call method."); + return; + } - var resolver = new JitAsmSymbolResolver(context.Runtime, methodAddress, methodLength, _settings); - var formatter = new IntelFormatter(FormatterOptions, resolver); - var output = new StringOutput(); - foreach (ref var instruction in instructions) { - formatter.Format(instruction, output); + if ((method.Attributes & MethodAttributes.PinvokeImpl) == MethodAttributes.PinvokeImpl) { + WriteSignatureFromReflection(context, method); + context.Writer.WriteLine(" ; Cannot produce JIT assembly for a P/Invoke method."); + return; + } - writer.Write(" L"); - writer.Write((instruction.IP - methodAddress).ToString("x4")); - writer.Write(": "); - writer.WriteLine(output.ToStringAndReset()); - } + if (method.DeclaringType?.IsGenericTypeDefinition ?? false) { + WriteIgnoredOpenGeneric(context, method); + return; } - private ClrMethodData? FindJitCompiledMethod(JitWriteContext context, RuntimeMethodHandle handle) { - context.Runtime.FlushCachedData(); - var sos = context.Runtime.DacLibrary.SOSDacInterface; + if (method.IsGenericMethodDefinition) { + DisassembleAndWriteGenericMethod(context, (MethodInfo)method); + return; + } - var methodDescAddress = unchecked((ulong)handle.Value.ToInt64()); - if (!sos.GetMethodDescData(methodDescAddress, 0, out var methodDesc)) - return null; + DisassembleAndWriteSimpleMethod(context, method); + } - return GetJitCompiledMethodByMethodDescIfValid(sos, methodDesc) - ?? FindJitCompiledMethodInMethodTable(sos, methodDesc); + private void DisassembleAndWriteGenericMethod(JitWriteContext context, MethodInfo method) { + var hasAttribute = false; + foreach (var attribute in method.GetCustomAttributes()) { + hasAttribute = true; + var genericInstance = ApplyJitGenericAttribute(method, attribute.ArgumentTypes, static (m, a) => m.MakeGenericMethod(a)); + DisassembleAndWriteSimpleMethod(context, genericInstance); } + if (!hasAttribute) + WriteIgnoredOpenGeneric(context, method); + } - private ClrMethodData? GetJitCompiledMethodByMethodDescIfValid(SOSDac sos, MethodDescData methodDesc) { - // https://github.com/microsoft/clrmd/issues/935 - var codeHeaderAddress = methodDesc.HasNativeCode != 0 - ? (ulong)methodDesc.NativeCodeAddr - : sos.GetMethodTableSlot(methodDesc.MethodTable, methodDesc.SlotNumber); + private void DisassembleAndWriteSimpleMethod(JitWriteContext context, MethodBase method) { + var handle = method.MethodHandle; + RuntimeHelpers.PrepareMethod(handle); - if (codeHeaderAddress == unchecked((ulong)-1)) - return null; + var clrMethodData = FindJitCompiledMethod(context.Runtime, method.MethodHandle); - if (!sos.GetCodeHeaderData(codeHeaderAddress, out var codeHeader)) - return null; + var writer = context.Writer; + if (clrMethodData?.Signature is {} signature) { + writer.WriteLine(); + writer.WriteLine(signature); + } + else { + WriteSignatureFromReflection(context, method); + } - return GetJitCompiledMethodByCodeHeaderIfValid(sos, codeHeader); + if (clrMethodData == null) { + writer.WriteLine(" ; Failed to find JIT output. This might appear more frequently than before due to a library update."); + writer.WriteLine(" ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress."); + return; } - private ClrMethodData? GetJitCompiledMethodByCodeHeaderIfValid(SOSDac sos, CodeHeaderData codeHeader) { - if (codeHeader.MethodStart.Value == -1 || codeHeader.HotRegionSize == 0) - return null; + var methodAddress = clrMethodData.Value.MethodAddress; + var methodLength = clrMethodData.Value.MethodSize; - return new( - sos.GetMethodDescName(codeHeader.MethodDesc), - unchecked((ulong)codeHeader.MethodStart.Value), - codeHeader.HotRegionSize - ); - } + var reader = new MemoryCodeReader(new IntPtr(unchecked((long)methodAddress)), methodLength); + var decoder = Decoder.Create(MapArchitectureToBitness(context.Runtime.DataTarget.DataReader.Architecture), reader); - private ClrMethodData? FindJitCompiledMethodInMethodTable(SOSDac sos, MethodDescData originalMethodDesc) { - // I can't really explain this, but it seems that some methods - // are present multiple times in the same type -- one compiled - // and one not compiled. + var instructions = new InstructionList(); + decoder.IP = methodAddress; + while (decoder.IP < (methodAddress + methodLength)) { + decoder.Decode(out instructions.AllocUninitializedElement()); + } - if (!sos.GetMethodTableData(originalMethodDesc.MethodTable, out var methodTable)) - return null; + var resolver = new JitAsmSymbolResolver(context.Runtime, methodAddress, methodLength, _settings); + var formatter = new IntelFormatter(FormatterOptions, resolver); + var output = new StringOutput(); + foreach (ref var instruction in instructions) { + formatter.Format(instruction, output); - ClrMethodData? methodData = null; - for (var i = 0u; i < methodTable.NumMethods; i++) { - if (i == originalMethodDesc.SlotNumber) - continue; + writer.Write(" L"); + writer.Write((instruction.IP - methodAddress).ToString("x4")); + writer.Write(": "); + writer.WriteLine(output.ToStringAndReset()); + } + } - var slot = sos.GetMethodTableSlot(originalMethodDesc.MethodTable, i); - if (!sos.GetCodeHeaderData(slot, out var candidateCodeHeader)) - continue; + private ClrMethodData? FindJitCompiledMethod(ClrRuntime runtime, RuntimeMethodHandle handle) { + lock (runtime) + runtime.FlushCachedData(); - if (!sos.GetMethodDescData(candidateCodeHeader.MethodDesc, 0, out var candidateMethodDesc)) - continue; + var methodDescAddress = unchecked((ulong)handle.Value.ToInt64()); + if (runtime.GetMethodByHandle(methodDescAddress) is not { } method) { + #if DEBUG + DiagnosticLog.LogMessage($"[JitAsm] Failed to GetMethodByHandle(0x{methodDescAddress:X})."); + #endif + return null; + } - if (candidateMethodDesc.MDToken != originalMethodDesc.MDToken) - continue; + if (method.CompilationType == MethodCompilationType.None) { + #if DEBUG + DiagnosticLog.LogMessage($"[JitAsm] Method {method.Signature} compilation type is None."); + #endif + return null; + } - methodData = GetJitCompiledMethodByCodeHeaderIfValid(sos, candidateCodeHeader); - if (methodData != null) - break; - } - return methodData; + if (method.NativeCode == 0) { + #if DEBUG + DiagnosticLog.LogMessage($"[JitAsm] Method {method.Signature} native code is 0."); + #endif + return null; } - private void WriteIgnoredOpenGeneric(JitWriteContext context, MethodBase method) { - WriteSignatureFromReflection(context, method); - var writer = context.Writer; - writer.WriteLine(" ; Open generics cannot be JIT-compiled."); - writer.WriteLine(" ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types."); - writer.WriteLine(" ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }."); + if (method.HotColdInfo.HotSize == 0) { + #if DEBUG + DiagnosticLog.LogMessage($"[JitAsm] Method {method.Signature} hot size is 0."); + #endif + return null; } - private void WriteSignatureFromReflection(JitWriteContext context, MethodBase method) { - context.Writer.WriteLine(); + return new( + method.Signature, + method.NativeCode, + method.HotColdInfo.HotSize + ); + } - var md = (ulong)method.MethodHandle.Value.ToInt64(); - var signature = context.Runtime.DacLibrary.SOSDacInterface.GetMethodDescName(md); + private void WriteIgnoredOpenGeneric(JitWriteContext context, MethodBase method) { + WriteSignatureFromReflection(context, method); + var writer = context.Writer; + writer.WriteLine(" ; Open generics cannot be JIT-compiled."); + writer.WriteLine(" ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types."); + writer.WriteLine(" ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }."); + } + + private void WriteSignatureFromReflection(JitWriteContext context, MethodBase method) { + var writer = context.Writer; - context.Writer.WriteLine(signature ?? "Unknown Method"); + writer.WriteLine(); + if (method.DeclaringType is { } declaringType) { + writer.Write(declaringType.FullName); + writer.Write("."); } - private TMember ApplyJitGenericAttribute(TMember definition, Type[] arguments, Func makeGeneric) - where TMember : MemberInfo - { - try { - return makeGeneric(definition, arguments); - } - catch (ArgumentException ex) { - throw new JitGenericAttributeException($"Failed to apply JitGenericAttribute to {definition.Name}: {ex.Message}", ex); - } - catch (Exception ex) when ( - ex is BadImageFormatException or TypeLoadException - && arguments.FirstOrDefault(static a => a.IsByRefLike) is {} refStructArgument - ) { - throw new JitGenericAttributeException($"JitGenericAttribute argument {refStructArgument.Name} is a ref struct, which is not supported in generics.", ex); + writer.Write(method.Name); + if (method.IsGenericMethod) { + writer.Write("[["); + var first = true; + foreach (var type in method.GetGenericArguments()) { + if (first) { + first = false; + } + else { + writer.Write(", "); + } + writer.Write(type.FullName); + writer.Write(", "); + writer.Write(type.Assembly.GetName().Name); } + writer.Write("]]"); } - private int MapArchitectureToBitness(Architecture architecture) => architecture switch - { - Architecture.Amd64 => 64, - Architecture.X86 => 32, - _ => throw new Exception($"Unsupported architecture {architecture}.") - }; + writer.WriteLine(method.GetParameters().Length > 0 ? "(...)" : "()"); + } - private class JitWriteContext { - public JitWriteContext(TextWriter writer, ClrRuntime runtime) { - Writer = writer; - Runtime = runtime; - } - - public TextWriter Writer { get; } - public ClrRuntime Runtime { get; } + private TMember ApplyJitGenericAttribute(TMember definition, Type[] arguments, Func makeGeneric) + where TMember : MemberInfo + { + try { + return makeGeneric(definition, arguments); + } + catch (ArgumentException ex) { + throw new JitGenericAttributeException($"Failed to apply JitGenericAttribute to {definition.Name}: {ex.Message}", ex); + } + catch (Exception ex) when ( + ex is BadImageFormatException or TypeLoadException + && arguments.FirstOrDefault(static a => a.IsByRefLike) is {} refStructArgument + ) { + throw new JitGenericAttributeException($"JitGenericAttribute argument {refStructArgument.Name} is a ref struct, which is not supported in generics.", ex); } + } - private readonly struct ClrMethodData { - public ClrMethodData(string? signature, ulong methodAddress, uint methodSize) { - Signature = signature; - MethodAddress = methodAddress; - MethodSize = methodSize; - } + private int MapArchitectureToBitness(Architecture architecture) => architecture switch + { + Architecture.X64 => 64, + Architecture.X86 => 32, + _ => throw new Exception($"Unsupported architecture {architecture}.") + }; + + private class JitWriteContext { + public JitWriteContext(TextWriter writer, ClrRuntime runtime) { + Writer = writer; + Runtime = runtime; + } + + public TextWriter Writer { get; } + public ClrRuntime Runtime { get; } + } - public string? Signature { get; } - public ulong MethodAddress { get; } - public uint MethodSize { get; } + private readonly struct ClrMethodData { + public ClrMethodData(string? signature, ulong methodAddress, uint methodSize) { + Signature = signature; + MethodAddress = methodAddress; + MethodSize = methodSize; } + + public string? Signature { get; } + public ulong MethodAddress { get; } + public uint MethodSize { get; } } } \ No newline at end of file diff --git a/source/Server/Execution/Container/ContainerExperimentMetrics.cs b/source/Server/Execution/Container/ContainerExperimentMetrics.cs deleted file mode 100644 index 0ce31b969..000000000 --- a/source/Server/Execution/Container/ContainerExperimentMetrics.cs +++ /dev/null @@ -1,8 +0,0 @@ -using SharpLab.Server.Monitoring; - -namespace SharpLab.Server.Execution.Container { - public static class ContainerExperimentMetrics { - public static MonitorMetric ContainerRunCount { get; } = new("container-experiment", "Runs: Container"); - public static MonitorMetric ContainerFailureCount { get; } = new("container-experiment", "Runs: Failed"); - } -} diff --git a/source/Server/Execution/ContainerExecutor.cs b/source/Server/Execution/ContainerExecutor.cs index 1f1e2dd3f..71e1cea51 100644 --- a/source/Server/Execution/ContainerExecutor.cs +++ b/source/Server/Execution/ContainerExecutor.cs @@ -1,12 +1,7 @@ -using System.Collections.Generic; using System.Diagnostics; -using System.IO; using System.Threading; using System.Threading.Tasks; -using Microsoft.IO; using MirrorSharp.Advanced; -using Mono.Cecil; -using Mono.Cecil.Cil; using SharpLab.Server.Common; using SharpLab.Server.Execution.Container; using SharpLab.Server.Execution.Internal; @@ -14,50 +9,28 @@ namespace SharpLab.Server.Execution { public class ContainerExecutor : IContainerExecutor { - private readonly IAssemblyResolver _assemblyResolver; - private readonly ISymbolReaderProvider _symbolReaderProvider; - private readonly IReadOnlyCollection _rewriters; - private readonly RecyclableMemoryStreamManager _memoryStreamManager; + private readonly IAssemblyStreamRewriterComposer _rewriterComposer; private readonly IContainerClient _client; public ContainerExecutor( - IAssemblyResolver assemblyResolver, - ISymbolReaderProvider symbolReaderProvider, - IReadOnlyCollection rewriters, - RecyclableMemoryStreamManager memoryStreamManager, + IAssemblyStreamRewriterComposer rewriterComposer, IContainerClient client ) { - _assemblyResolver = assemblyResolver; - _symbolReaderProvider = symbolReaderProvider; - _rewriters = rewriters; - _memoryStreamManager = memoryStreamManager; + _rewriterComposer = rewriterComposer; _client = client; } public async Task ExecuteAsync(CompilationStreamPair streams, IWorkSession session, CancellationToken cancellationToken) { - var includePerformance = session.ShouldReportPerformance(); - var rewriteStopwatch = includePerformance ? Stopwatch.StartNew() : null; - var readerParameters = new ReaderParameters { - ReadSymbols = streams.SymbolStream != null, - SymbolStream = streams.SymbolStream, - AssemblyResolver = _assemblyResolver, - SymbolReaderProvider = streams.SymbolStream != null ? _symbolReaderProvider : null - }; - - using var definition = AssemblyDefinition.ReadAssembly(streams.AssemblyStream, readerParameters); + Argument.NotNull(nameof(streams), streams); + Argument.NotNull(nameof(session), session); - foreach (var rewriter in _rewriters) { - rewriter.Rewrite(definition, session); - } - - using var rewrittenStream = _memoryStreamManager.GetStream(); - definition.Write(rewrittenStream); - rewrittenStream.Seek(0, SeekOrigin.Begin); - rewriteStopwatch?.Stop(); + using var rewritten = _rewriterComposer.Rewrite(streams, session); + var includePerformance = session.ShouldReportPerformance(); var executeStopwatch = includePerformance ? Stopwatch.StartNew() : null; - var result = await _client.ExecuteAsync(session.GetSessionId(), rewrittenStream, includePerformance, cancellationToken); - if (rewriteStopwatch != null && executeStopwatch != null) { + var result = await _client.ExecuteAsync(session.GetSessionId(), rewritten.Stream, includePerformance, cancellationToken); + + if (rewritten.ElapsedTime != null && executeStopwatch != null) { // TODO: Prettify // output += $"\n REWRITERS: {rewriteStopwatch.ElapsedMilliseconds,17}ms\n CONTAINER EXECUTOR: {executeStopwatch.ElapsedMilliseconds,8}ms"; } diff --git a/source/Server/Execution/ExecutionModule.cs b/source/Server/Execution/ExecutionModule.cs index 46f6e1f8d..c2668a600 100644 --- a/source/Server/Execution/ExecutionModule.cs +++ b/source/Server/Execution/ExecutionModule.cs @@ -7,47 +7,47 @@ using SharpLab.Server.Execution.Container; using SharpLab.Server.Execution.Internal; -namespace SharpLab.Server.Execution { - [UsedImplicitly] - public class ExecutionModule : Module { - protected override void Load(ContainerBuilder builder) { - var containerHostUrl = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_CONTAINER_HOST_URL"); - - builder.Register(_ => { - var dataTarget = DataTarget.AttachToProcess(Current.ProcessId, suspend: false); - return dataTarget.ClrVersions.Single(c => c.Flavor == ClrFlavor.Core).CreateRuntime(); - }).SingleInstance(); - - builder.RegisterType>() - .AsSelf() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.Register(c => { - var secretsClient = c.Resolve(); - var containerAuthorizationToken = secretsClient.GetSecret("ContainerHostAuthorizationToken"); - return new ContainerClientSettings(new Uri(containerHostUrl), containerAuthorizationToken); - }).SingleInstance() - .AsSelf(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - } +namespace SharpLab.Server.Execution; + +[UsedImplicitly] +public class ExecutionModule : Module { + protected override void Load(ContainerBuilder builder) { + var containerHostUrl = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_CONTAINER_HOST_URL"); + + builder.Register(_ => { + var dataTarget = DataTarget.AttachToProcess(Current.ProcessId, suspend: false); + return dataTarget.ClrVersions.Single(c => c.Flavor == ClrFlavor.Core).CreateRuntime(); + }).SingleInstance(); + + builder.RegisterType>() + .AsSelf() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.Register(c => { + var secretsClient = c.Resolve(); + var containerAuthorizationToken = secretsClient.GetSecret("ContainerHostAuthorizationToken"); + return new ContainerClientSettings(new Uri(containerHostUrl), containerAuthorizationToken); + }).SingleInstance() + .AsSelf(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); } } \ No newline at end of file diff --git a/source/Server/Execution/Internal/AssemblyRewriteResult.cs b/source/Server/Execution/Internal/AssemblyRewriteResult.cs new file mode 100644 index 000000000..85cbda365 --- /dev/null +++ b/source/Server/Execution/Internal/AssemblyRewriteResult.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using Mono.Cecil; + +namespace SharpLab.Server.Execution.Internal { + public readonly struct AssemblyStreamRewriteResult : IDisposable { + private readonly ModuleDefinition _module; + + public AssemblyStreamRewriteResult(Stream stream, TimeSpan? elapsedTime, ModuleDefinition module) { + Stream = stream; + ElapsedTime = elapsedTime; + _module = module; + } + + public Stream Stream { get; } + public TimeSpan? ElapsedTime { get; } + + public void Dispose() { + var moduleDisposeException = (Exception?)null; + try { + _module.Dispose(); + } + catch (Exception ex) { + moduleDisposeException = ex; + } + + try { + Stream.Dispose(); + } + catch (Exception ex) when (moduleDisposeException != null) { + throw new AggregateException(moduleDisposeException, ex); + } + } + } +} diff --git a/source/Server/Execution/Internal/AssemblyStreamRewriterComposer.cs b/source/Server/Execution/Internal/AssemblyStreamRewriterComposer.cs new file mode 100644 index 000000000..4c38d010e --- /dev/null +++ b/source/Server/Execution/Internal/AssemblyStreamRewriterComposer.cs @@ -0,0 +1,90 @@ +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.IO; +using MirrorSharp.Advanced; +using Mono.Cecil; +using Mono.Cecil.Cil; +using SharpLab.Runtime; +using SharpLab.Server.Common; +using SharpLab.Server.Common.Diagnostics; +using SharpLab.Server.MirrorSharp; + +namespace SharpLab.Server.Execution.Internal { + public class AssemblyStreamRewriterComposer : IAssemblyStreamRewriterComposer { + private readonly IAssemblyResolver _assemblyResolver; + private readonly ISymbolReaderProvider _symbolReaderProvider; + private readonly IReadOnlyCollection _rewriters; + private readonly RecyclableMemoryStreamManager _memoryStreamManager; + + public AssemblyStreamRewriterComposer( + IAssemblyResolver assemblyResolver, + ISymbolReaderProvider symbolReaderProvider, + IReadOnlyCollection rewriters, + RecyclableMemoryStreamManager memoryStreamManager + ) { + _assemblyResolver = assemblyResolver; + _symbolReaderProvider = symbolReaderProvider; + _rewriters = rewriters; + _memoryStreamManager = memoryStreamManager; + } + + public AssemblyStreamRewriteResult Rewrite(CompilationStreamPair streams, IWorkSession session) { + var includePerformance = session.ShouldReportPerformance(); + var rewriteStopwatch = includePerformance ? Stopwatch.StartNew() : null; + var readerParameters = new ReaderParameters { + ReadSymbols = streams.SymbolStream != null, + SymbolStream = streams.SymbolStream, + AssemblyResolver = _assemblyResolver, + SymbolReaderProvider = streams.SymbolStream != null ? _symbolReaderProvider : null + }; + + var module = ModuleDefinition.ReadModule(streams.AssemblyStream, readerParameters); + try { + if (module.Assembly is {} assembly && HasNoRewritingAttribute(assembly)) { + streams.AssemblyStream.Position = 0; + return new(streams.AssemblyStream, null, module); + } + + return RewriteInternal(module, session, rewriteStopwatch); + } + catch { + module.Dispose(); + throw; + } + } + + private AssemblyStreamRewriteResult RewriteInternal(ModuleDefinition module, IWorkSession session, Stopwatch? rewriteStopwatch) { + foreach (var rewriter in _rewriters) { + rewriter.Rewrite(module, session); + } + + #if DEBUG + DiagnosticLog.LogAssembly("2.WithFlow", module); + #endif + + var rewrittenStream = _memoryStreamManager.GetStream(); + try { + module.Write(rewrittenStream); + rewrittenStream.Position = 0; + rewriteStopwatch?.Stop(); + return new(rewrittenStream, rewriteStopwatch?.Elapsed, module); + } + catch { + rewrittenStream.Dispose(); + throw; + } + } + + private bool HasNoRewritingAttribute(AssemblyDefinition assembly) { + if (!assembly.HasCustomAttributes) + return false; + + foreach (var attribute in assembly.CustomAttributes) { + if (attribute.AttributeType.Name == nameof(NoILRewritingAttribute)) + return true; + } + + return false; + } + } +} diff --git a/source/Server/Execution/Internal/CecilExtensions.cs b/source/Server/Execution/Internal/CecilExtensions.cs index 6e0e42a9a..c481152ec 100644 --- a/source/Server/Execution/Internal/CecilExtensions.cs +++ b/source/Server/Execution/Internal/CecilExtensions.cs @@ -68,6 +68,25 @@ public static Instruction CreateLdcI4Best(this ILProcessor il, int value) { } } + + public static int? GetLdcI4Value(this Instruction instruction) { + return instruction.OpCode.Code switch { + Code.Ldc_I4_0 => 0, + Code.Ldc_I4_1 => 1, + Code.Ldc_I4_2 => 2, + Code.Ldc_I4_3 => 3, + Code.Ldc_I4_4 => 4, + Code.Ldc_I4_5 => 5, + Code.Ldc_I4_6 => 6, + Code.Ldc_I4_7 => 7, + Code.Ldc_I4_8 => 8, + Code.Ldc_I4_M1 => -1, + Code.Ldc_I4_S => (sbyte)instruction.Operand, + Code.Ldc_I4 => (int)instruction.Operand, + _ => null + }; + } + private static bool IsSByte(int value) { return value >= sbyte.MinValue && value <= sbyte.MaxValue; } @@ -76,28 +95,6 @@ public static Instruction CreateCall(this ILProcessor il, MethodReference method return il.Create(OpCodes.Call, method); } - public static void InsertBeforeAndRetargetAll(this ILProcessor il, Instruction target, Instruction instruction) { - il.InsertBefore(target, instruction); - RetargetAll(il, target, instruction); - } - - private static void RetargetAll(this ILProcessor il, Instruction from, Instruction to) { - foreach (var other in il.Body.Instructions) { - if (other == to) - continue; - - if (other.Operand == from) - other.Operand = to; - } - - if (!il.Body.HasExceptionHandlers) - return; - - foreach (var handler in il.Body.ExceptionHandlers) { - handler.RetargetAll(from, to); - } - } - public static void RetargetAll(this ExceptionHandler handler, Instruction from, Instruction to) { if (handler.TryStart == from) handler.TryStart = to; diff --git a/source/Server/Execution/Internal/ContainerFlowReportingRewriter.cs b/source/Server/Execution/Internal/ContainerFlowReportingRewriter.cs deleted file mode 100644 index 3a8b583dd..000000000 --- a/source/Server/Execution/Internal/ContainerFlowReportingRewriter.cs +++ /dev/null @@ -1,334 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using MirrorSharp.Advanced; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Cecil.Rocks; -using SharpLab.Runtime.Internal; -using SharpLab.Server.Common; - -namespace SharpLab.Server.Execution.Internal { - public class ContainerFlowReportingRewriter : IContainerAssemblyRewriter { - private const int HiddenLine = 0xFEEFEE; - - private static readonly MethodInfo ReportLineStartMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportLineStart))!; - private static readonly MethodInfo ReportValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportValue))!; - private static readonly MethodInfo ReportRefValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportRefValue))!; - private static readonly MethodInfo ReportSpanValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportSpanValue))!; - private static readonly MethodInfo ReportRefSpanValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportRefSpanValue))!; - private static readonly MethodInfo ReportReadOnlySpanValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportReadOnlySpanValue))!; - private static readonly MethodInfo ReportRefReadOnlySpanValueMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportRefReadOnlySpanValue))!; - private static readonly MethodInfo ReportExceptionMethod = - typeof(ContainerFlow).GetMethod(nameof(ContainerFlow.ReportException))!; - - private readonly IReadOnlyDictionary _languages; - - public ContainerFlowReportingRewriter(IReadOnlyList languages) { - _languages = languages.ToDictionary(l => l.LanguageName); - } - - public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { - foreach (var module in assembly.Modules) { - foreach (var type in module.Types) { - if (HasFlowSupressingCalls(type)) - return; - } - } - - foreach (var module in assembly.Modules) { - var flow = new ReportMethods { - ReportLineStart = module.ImportReference(ReportLineStartMethod), - ReportValue = module.ImportReference(ReportValueMethod), - ReportRefValue = module.ImportReference(ReportRefValueMethod), - ReportSpanValue = module.ImportReference(ReportSpanValueMethod), - ReportRefSpanValue = module.ImportReference(ReportRefSpanValueMethod), - ReportReadOnlySpanValue = module.ImportReference(ReportReadOnlySpanValueMethod), - ReportRefReadOnlySpanValue = module.ImportReference(ReportRefReadOnlySpanValueMethod), - ReportException = module.ImportReference(ReportExceptionMethod), - }; - foreach (var type in module.Types) { - Rewrite(type, flow, session); - } - } - } - - private bool HasFlowSupressingCalls(TypeDefinition type) { - foreach (var method in type.Methods) { - if (!method.HasBody || method.Body.Instructions.Count == 0) - continue; - foreach (var instruction in method.Body.Instructions) { - if (instruction.OpCode.FlowControl == FlowControl.Call && IsFlowSuppressing((MethodReference)instruction.Operand)) - return true; - } - } - - foreach (var nested in type.NestedTypes) { - if (HasFlowSupressingCalls(nested)) - return true; - } - - return false; - } - - private bool IsFlowSuppressing(MethodReference callee) { - return callee.Name == nameof(Inspect.Allocations) - && callee.DeclaringType.Name == nameof(Inspect); - } - - private void Rewrite(TypeDefinition type, ReportMethods flow, IWorkSession session) { - foreach (var method in type.Methods) { - Rewrite(method, flow, session); - } - - foreach (var nested in type.NestedTypes) { - Rewrite(nested, flow, session); - } - } - - private void Rewrite(MethodDefinition method, ReportMethods flow, IWorkSession session) { - if (!method.HasBody || method.Body.Instructions.Count == 0) - return; - - method.Body.SimplifyMacros(); - - var il = method.Body.GetILProcessor(); - var instructions = il.Body.Instructions; - var lastLine = (int?)null; - for (var i = 0; i < instructions.Count; i++) { - var instruction = instructions[i]; - var sequencePoint = method.DebugInformation?.GetSequencePoint(instruction); - var hasSequencePoint = sequencePoint != null && sequencePoint.StartLine != HiddenLine; - if (!hasSequencePoint && lastLine == null) - continue; - - if (hasSequencePoint && sequencePoint!.StartLine != lastLine) { - if (i == 0) - TryInsertReportMethodArguments(il, instruction, sequencePoint, method, flow, session, ref i); - - il.InsertBeforeAndRetargetAll(instruction, il.CreateLdcI4Best(sequencePoint.StartLine)); - il.InsertBefore(instruction, il.CreateCall(flow.ReportLineStart)); - i += 2; - lastLine = sequencePoint.StartLine; - } - - var valueOrNull = GetValueToReport(instruction, il, session); - if (valueOrNull == null) - continue; - - var value = valueOrNull.Value; - InsertReportValue( - il, instruction, - il.Create(OpCodes.Dup), value.type, value.name, - sequencePoint?.StartLine ?? lastLine ?? ContainerFlow.UnknownLineNumber, - flow, ref i - ); - } - - RewriteExceptionHandlers(il, flow); - - method.Body.OptimizeMacros(); - } - - private void TryInsertReportMethodArguments(ILProcessor il, Instruction instruction, SequencePoint sequencePoint, MethodDefinition method, ReportMethods flow, IWorkSession session, ref int index) { - if (!method.HasParameters) - return; - - var parameterLines = _languages[session.LanguageName] - .GetMethodParameterLines(session, sequencePoint.StartLine, sequencePoint.StartColumn); - - if (parameterLines.Length == 0) - return; - - // Note: method parameter lines are unreliable and can potentially return - // wrong lines if nested method syntax is unrecognized and code matches it - // to the containing method. That is acceptable, as long as parameter count - // mismatch does not crash things -> so check length here. - if (parameterLines.Length != method.Parameters.Count) - return; - - foreach (var parameter in method.Parameters) { - if (parameter.IsOut) - continue; - - InsertReportValue( - il, instruction, - il.CreateLdargBest(parameter), parameter.ParameterType, parameter.Name, - parameterLines[parameter.Index], flow, - ref index - ); - } - } - - private (string name, TypeReference type)? GetValueToReport(Instruction instruction, ILProcessor il, IWorkSession session) { - var localIndex = GetIndexIfStloc(instruction); - if (localIndex != null) { - var variable = il.Body.Variables[localIndex.Value]; - var symbols = il.Body.Method.DebugInformation; - if (symbols == null || !symbols.TryGetName(variable, out var variableName)) - return null; - - return (variableName, variable.VariableType); - } - - if (instruction.OpCode.Code == Code.Ret) { - if (instruction.Previous?.Previous?.OpCode.Code == Code.Tail) - return null; - var method = il.Body.Method; - if (method.ReturnsVoid()) - return null; - return ("return", method.ReturnType); - } - - return null; - } - - private void InsertReportValue( - ILProcessor il, - Instruction instruction, - Instruction getValue, - TypeReference valueType, - string valueName, - int line, - ReportMethods flow, - ref int index - ) { - il.InsertBeforeAndRetargetAll(instruction, getValue); - il.InsertBefore(instruction, valueName != null ? il.Create(OpCodes.Ldstr, valueName) : il.Create(OpCodes.Ldnull)); - il.InsertBefore(instruction, il.CreateLdcI4Best(line)); - - if (valueType is RequiredModifierType requiredType) - valueType = requiredType.ElementType; // not the same as GetElementType() which unwraps nested ref-types etc - - var report = PrepareReportValue(valueType, flow.ReportValue, flow.ReportSpanValue, flow.ReportReadOnlySpanValue); - if (valueType is ByReferenceType byRef) - report = PrepareReportValue(byRef.ElementType, flow.ReportRefValue, flow.ReportRefSpanValue, flow.ReportRefReadOnlySpanValue); - - il.InsertBefore(instruction, il.CreateCall(report)); - index += 4; - } - - private GenericInstanceMethod PrepareReportValue(TypeReference valueType, MethodReference reportAnyNonSpan, MethodReference reportSpan, MethodReference reportReadOnlySpan) { - if (valueType is GenericInstanceType generic) { - if (generic.ElementType.FullName == "System.Span`1") - return new GenericInstanceMethod(reportSpan) { GenericArguments = { generic.GenericArguments[0] } }; - if (generic.ElementType.FullName == "System.ReadOnlySpan`1") - return new GenericInstanceMethod(reportReadOnlySpan) { GenericArguments = { generic.GenericArguments[0] } }; - } - - return new GenericInstanceMethod(reportAnyNonSpan) { GenericArguments = { valueType } }; - } - - private void RewriteExceptionHandlers(ILProcessor il, ReportMethods flow) { - if (!il.Body.HasExceptionHandlers) - return; - - var handlers = il.Body.ExceptionHandlers; - for (var i = 0; i < handlers.Count; i++) { - switch (handlers[i].HandlerType) { - case ExceptionHandlerType.Catch: - RewriteCatch(handlers[i].HandlerStart, il, flow); - break; - - case ExceptionHandlerType.Filter: - RewriteCatch(handlers[i].FilterStart, il, flow); - break; - - case ExceptionHandlerType.Finally: - RewriteFinally(handlers[i], ref i, il, flow); - break; - } - } - } - - private void RewriteCatch(Instruction start, ILProcessor il, ReportMethods flow) { - il.InsertBeforeAndRetargetAll(start, il.Create(OpCodes.Dup)); - il.InsertBefore(start, il.CreateCall(flow.ReportException)); - } - - private void RewriteFinally(ExceptionHandler handler, ref int handlerIndex, ILProcessor il, ReportMethods flow) { - // for try/finally, the only thing we can do is to - // wrap internals of try into a new try+filter+catch - var outerTryLeave = handler.TryEnd.Previous; - if (!outerTryLeave.OpCode.Code.IsLeave()) { - // in some cases (e.g. exception throw) outer handler does - // not end with `leave` -- but we do need it once we wrap - // that throw - - // if the handler is the last thing in the method - if (handler.HandlerEnd == null) - { - var finalReturn = il.Create(OpCodes.Ret); - il.Append(finalReturn); - handler.HandlerEnd = finalReturn; - } - - outerTryLeave = il.Create(OpCodes.Leave, handler.HandlerEnd); - il.InsertBefore(handler.TryEnd, outerTryLeave); - } - - var innerTryLeave = il.Create(OpCodes.Leave_S, outerTryLeave); - var reportCall = il.CreateCall(flow.ReportException); - var catchHandler = il.Create(OpCodes.Pop); - - il.InsertBeforeAndRetargetAll(outerTryLeave, innerTryLeave); - il.InsertBefore(outerTryLeave, reportCall); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Ldc_I4_0)); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Endfilter)); - il.InsertBefore(outerTryLeave, catchHandler); - il.InsertBefore(outerTryLeave, il.Create(OpCodes.Leave_S, outerTryLeave)); - - for (var i = 0; i < handlerIndex; i++) { - il.Body.ExceptionHandlers[i].RetargetAll(outerTryLeave.Next, innerTryLeave.Next); - } - - il.Body.ExceptionHandlers.Insert(handlerIndex, new ExceptionHandler(ExceptionHandlerType.Filter) { - TryStart = handler.TryStart, - TryEnd = reportCall, - FilterStart = reportCall, - HandlerStart = catchHandler, - HandlerEnd = outerTryLeave - }); - handlerIndex += 1; - } - - private void InsertAfter(ILProcessor il, ref Instruction target, ref int index, Instruction instruction) { - il.InsertAfter(target, instruction); - target = instruction; - index += 1; - } - - private int? GetIndexIfStloc(Instruction instruction) { - switch (instruction.OpCode.Code) { - case Code.Stloc_0: return 0; - case Code.Stloc_1: return 1; - case Code.Stloc_2: return 2; - case Code.Stloc_3: return 3; - - case Code.Stloc_S: - case Code.Stloc: - return ((VariableReference)instruction.Operand).Index; - - default: return null; - } - } - - private struct ReportMethods { - public MethodReference ReportLineStart { get; set; } - public MethodReference ReportValue { get; set; } - public MethodReference ReportRefValue { get; set; } - public MethodReference ReportSpanValue { get; set; } - public MethodReference ReportRefSpanValue { get; set; } - public MethodReference ReportReadOnlySpanValue { get; set; } - public MethodReference ReportRefReadOnlySpanValue { get; set; } - public MethodReference ReportException { get; set; } - } - } -} diff --git a/source/Server/Execution/Internal/FSharpEntryPointRewriter.cs b/source/Server/Execution/Internal/FSharpEntryPointRewriter.cs deleted file mode 100644 index 5db649033..000000000 --- a/source/Server/Execution/Internal/FSharpEntryPointRewriter.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Microsoft.FSharp.Core; -using MirrorSharp.Advanced; -using MirrorSharp.FSharp.Advanced; -using Mono.Cecil; - -namespace SharpLab.Server.Execution.Internal { - // There are some weird problems when I try to compile F# code as an exe (e.g. it tries to - // do filesystem operations without using the virtual filesystem), so instead I compile - // it as a library and then fake the entry point. - public class FSharpEntryPointRewriter : IContainerAssemblyRewriter { - public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { - if (!session.IsFSharp()) - return; - - if (assembly.EntryPoint != null) - return; - - var (entryPoint, isStaticConstructor) = FindBestEntryPointCandidate(assembly); - if (entryPoint == null) - return; - - if (isStaticConstructor) { - entryPoint.Attributes &= ~MethodAttributes.SpecialName & ~MethodAttributes.RTSpecialName; - entryPoint.Name = "cctor_rewritten_to_method_by_sharplab"; - } - assembly.EntryPoint = entryPoint; - } - - private (MethodDefinition? method, bool isStaticConstructor) FindBestEntryPointCandidate(AssemblyDefinition assembly) { - // First priority -- explicit [] - // Second priority -- top level code (gets compiled into a static ctor) - - MethodDefinition? startup = null; - foreach (var type in assembly.MainModule.Types) { - if (type.Namespace == "" && type.Name == "$_" && type.HasMethods) { - foreach (var method in type.Methods) { - if (method.IsConstructor && method.IsStatic) { - startup = method; - break; - } - } - continue; - } - - if (type.Namespace == "" && type.Name == "_" && type.HasMethods) { - foreach (var method in type.Methods) { - if (HasEntryPointAttribute(method)) - return (method, false); - } - } - } - - return (startup, startup != null); - } - - private bool HasEntryPointAttribute(MethodDefinition method) { - if (!method.HasCustomAttributes) - return false; - - foreach (var attribute in method.CustomAttributes) { - if (attribute.AttributeType.Namespace == "Microsoft.FSharp.Core" && attribute.AttributeType.Name == nameof(EntryPointAttribute)) - return true; - } - return false; - } - } -} \ No newline at end of file diff --git a/source/Server/Execution/Internal/FlowReportingRewriter.cs b/source/Server/Execution/Internal/FlowReportingRewriter.cs new file mode 100644 index 000000000..7038420bd --- /dev/null +++ b/source/Server/Execution/Internal/FlowReportingRewriter.cs @@ -0,0 +1,618 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using MirrorSharp.Advanced; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using SharpLab.Runtime.Internal; +using SharpLab.Server.Common; +using SharpLab.Server.Common.Diagnostics; + +namespace SharpLab.Server.Execution.Internal { + public class FlowReportingRewriter : IAssemblyRewriter { + private const int HiddenLine = 0xFEEFEE; + + private static readonly MethodInfo ReportMethodAreaMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportMethodArea))!; + private static readonly MethodInfo ReportLoopAreaMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportLoopArea))!; + + private static readonly MethodInfo ReportLineStartMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportLineStart))!; + + private static readonly MethodInfo ReportJumpMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportJump))!; + + private static readonly MethodInfo ReportValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportValue))!; + private static readonly MethodInfo ReportRefValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefValue))!; + private static readonly MethodInfo ReportSpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportSpanValue))!; + private static readonly MethodInfo ReportRefSpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefSpanValue))!; + private static readonly MethodInfo ReportReadOnlySpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportReadOnlySpanValue))!; + private static readonly MethodInfo ReportRefReadOnlySpanValueMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportRefReadOnlySpanValue))!; + + private static readonly MethodInfo ReportExceptionMethod = + typeof(Flow).GetMethod(nameof(Flow.ReportException))!; + + private readonly IReadOnlyDictionary _languages; + + public FlowReportingRewriter(IReadOnlyList languages) { + _languages = languages.ToDictionary(l => l.LanguageName); + } + + public void Rewrite(ModuleDefinition module, IWorkSession session) { + if (!module.HasTypes) + return; + + foreach (var type in module.Types) { + if (HasFlowSupressingCalls(type)) + return; + } + + var flow = new FlowMethods { + ReportMethodArea = module.ImportReference(ReportMethodAreaMethod), + ReportLoopArea = module.ImportReference(ReportLoopAreaMethod), + + ReportLineStart = module.ImportReference(ReportLineStartMethod), + + ReportJump = module.ImportReference(ReportJumpMethod), + + ReportValue = module.ImportReference(ReportValueMethod), + ReportRefValue = module.ImportReference(ReportRefValueMethod), + ReportSpanValue = module.ImportReference(ReportSpanValueMethod), + ReportRefSpanValue = module.ImportReference(ReportRefSpanValueMethod), + ReportReadOnlySpanValue = module.ImportReference(ReportReadOnlySpanValueMethod), + ReportRefReadOnlySpanValue = module.ImportReference(ReportRefReadOnlySpanValueMethod), + + ReportException = module.ImportReference(ReportExceptionMethod), + }; + foreach (var type in module.Types) { + Rewrite(type, flow, session); + } + + if (module.EntryPoint is not {} entryPoint) + return; + + var entryPointIL = entryPoint.Body.GetILProcessor(); + var insertIndex = 0; + foreach (var type in module.Types) { + TryInsertReportMethodAreaForAllMethods(entryPointIL, type, flow, ref insertIndex); + } + } + + private bool HasFlowSupressingCalls(TypeDefinition type) { + if (type.HasMethods) { + foreach (var method in type.Methods) { + if (!method.HasBody || method.Body.Instructions.Count == 0) + continue; + + foreach (var instruction in method.Body.Instructions) { + var isFlowSupressing = instruction.OpCode.FlowControl == FlowControl.Call + && instruction.Operand is MethodReference m + && IsFlowSuppressing(m); + + if (isFlowSupressing) + return true; + } + } + } + + if (type.HasNestedTypes) { + foreach (var nested in type.NestedTypes) { + if (HasFlowSupressingCalls(nested)) + return true; + } + } + + return false; + } + + private bool IsFlowSuppressing(MethodReference callee) { + return callee.Name == nameof(Inspect.Allocations) + && callee.DeclaringType.Name == nameof(Inspect); + } + + private void TryInsertReportMethodAreaForAllMethods(ILProcessor entryPointIL, TypeDefinition type, FlowMethods flow, ref int insertIndex) { + if (type.HasMethods) { + foreach (var method in type.Methods) { + TryInsertReportMethodArea(entryPointIL, method, flow, ref insertIndex); + } + } + + if (type.HasNestedTypes) { + foreach (var nested in type.NestedTypes) { + TryInsertReportMethodAreaForAllMethods(entryPointIL, nested, flow, ref insertIndex); + } + } + } + + private void TryInsertReportMethodArea(ILProcessor entryPointIL, MethodDefinition method, FlowMethods flow, ref int insertIndex) { + if (!method.HasBody || method.DebugInformation == null || method == entryPointIL.Body.Method) + return; + + var startLine = int.MaxValue; + var endLine = int.MinValue; + foreach (var instruction in method.Body.Instructions) { + var sequencePoint = method.DebugInformation.GetSequencePoint(instruction); + if (!HasLine(sequencePoint)) + continue; + + startLine = Math.Min(sequencePoint.StartLine, startLine); + endLine = Math.Max(sequencePoint.EndLine, endLine); + } + + if (startLine == int.MaxValue || endLine == int.MinValue) + return; + + entryPointIL.Body.Instructions.Insert(insertIndex, entryPointIL.CreateLdcI4Best(startLine)); + entryPointIL.Body.Instructions.Insert(insertIndex + 1, entryPointIL.CreateLdcI4Best(endLine)); + entryPointIL.Body.Instructions.Insert(insertIndex + 2, entryPointIL.CreateCall(flow.ReportMethodArea)); + insertIndex += 3; + } + + private void Rewrite(TypeDefinition type, FlowMethods flow, IWorkSession session) { + if (type.HasMethods) { + foreach (var method in type.Methods) { + Rewrite(method, flow, session); + } + } + + if (type.HasNestedTypes) { + foreach (var nested in type.NestedTypes) { + Rewrite(nested, flow, session); + } + } + } + + private void Rewrite(MethodDefinition method, FlowMethods flow, IWorkSession session) { + if (!method.HasBody || method.Body.Instructions.Count == 0) + return; + + if (method.DebugInformation is not {} debug) + return; + + method.Body.SimplifyMacros(); + + var il = method.Body.GetILProcessor(); + LogILIfEnabled(il, ILLogStep.Initial); + + var instructions = il.Body.Instructions; + var lastLine = (int?)null; + var lastLoopReportIndex = 0; + for (var i = 0; i < instructions.Count; i++) { + var instruction = instructions[i]; + + var sequencePoint = debug.GetSequencePoint(instruction); + var hasLine = HasLine(sequencePoint); + if (!hasLine && lastLine == null) + continue; + + if (hasLine && sequencePoint!.StartLine != lastLine) { + var isMethodStart = i == 0; + if (isMethodStart) + TryInsertReportMethodArguments(il, instruction, sequencePoint, method, flow, session, ref i); + + SafeInsertBeforeAndRetargetAll(il, instruction, il.CreateLdcI4Best(sequencePoint.StartLine)); + il.InsertBefore(instruction, il.CreateCall(flow.ReportLineStart)); + i += 2; + + lastLine = sequencePoint.StartLine; + } + + if (ShouldReportAsJump(instruction, method)) { + SafeInsertBeforeAndRetargetAll(il, instruction, il.CreateCall(flow.ReportJump)); + LogILIfEnabled(il, ILLogStep.AfterReportJump, i.ToString()); + i += 1; + } + + TryInsertReportLoopArea(il, instruction, debug, flow, ref i, ref lastLoopReportIndex); + + var valueOrNull = GetValueToReport(instruction, il, session); + if (valueOrNull == null) + continue; + + var value = valueOrNull.Value; + InsertReportValue( + il, instruction, + il.Create(OpCodes.Dup), value.type, value.name, + sequencePoint?.StartLine ?? lastLine ?? Flow.UnknownLineNumber, + flow, ref i + ); + } + + RewriteExceptionHandlers(il, flow); + + method.Body.OptimizeMacros(); + LogILIfEnabled(il, ILLogStep.Final); + } + + private static bool ShouldReportAsJump(Instruction instruction, MethodDefinition method) { + return instruction.OpCode.FlowControl switch { + FlowControl.Branch or FlowControl.Cond_Branch => true, + + // only calls to same-module methods + FlowControl.Call => instruction.Operand is MethodDefinition, + + // do not include final return of the entrypoint + FlowControl.Return => method != method.Module.EntryPoint, + + _ => false + }; + } + + private void TryInsertReportMethodArguments(ILProcessor il, Instruction instruction, SequencePoint sequencePoint, MethodDefinition method, FlowMethods flow, IWorkSession session, ref int index) { + if (!method.HasParameters) + return; + + var parameterLines = _languages[session.LanguageName] + .GetMethodParameterLines(session, sequencePoint.StartLine, sequencePoint.StartColumn); + + if (parameterLines.Length == 0) + return; + + // Note: method parameter lines are unreliable and can potentially return + // wrong lines if nested method syntax is unrecognized and code matches it + // to the containing method. That is acceptable, as long as parameter count + // mismatch does not crash things -> so check length here. + if (parameterLines.Length != method.Parameters.Count) + return; + + foreach (var parameter in method.Parameters) { + if (parameter.IsOut) + continue; + + InsertReportValue( + il, instruction, + il.CreateLdargBest(parameter), parameter.ParameterType, parameter.Name, + parameterLines[parameter.Index], flow, + ref index + ); + } + } + + private void TryInsertReportLoopArea( + ILProcessor il, + Instruction instruction, + MethodDebugInformation debug, + FlowMethods flow, + ref int index, + ref int lastLoopReportIndex + ) { + if (instruction.OpCode.FlowControl != FlowControl.Cond_Branch) + return; + + if (instruction.Operand is not Instruction start) + return; + + if (start.Offset >= instruction.Offset) + return; + + var startPoint = debug.GetSequencePoint(start); + if (!HasLine(startPoint)) + return; + + var startLine = startPoint.StartLine; + if (FindLoopEndLine(instruction, start, startLine, debug, flow) is not {} endLine) + return; + + il.Body.Instructions.Insert(lastLoopReportIndex, il.CreateLdcI4Best(startLine)); + il.Body.Instructions.Insert(lastLoopReportIndex + 1, il.CreateLdcI4Best(endLine)); + il.Body.Instructions.Insert(lastLoopReportIndex + 2, il.CreateCall(flow.ReportLoopArea)); + lastLoopReportIndex += 3; + index += 3; + } + + private int? FindLoopEndLine(Instruction end, Instruction start, int startLine, MethodDebugInformation debug, FlowMethods flow) { + // Naive approach to end line can sometimes capture start line instead. + // For something like 'while (condition)' in C# the condition is + // located on the line of 'while', but in IL it is checked _before_ the + // jump back. + var previous = end.Previous; + while (previous != null && previous != start) { + var point = debug.GetSequencePoint(previous); + if (HasLine(point) && point.EndLine > startLine) + return point.EndLine; + previous = previous.Previous; + } + return null; + } + + private (string name, TypeReference type)? GetValueToReport(Instruction instruction, ILProcessor il, IWorkSession session) { + var localIndex = GetIndexIfStloc(instruction); + if (localIndex != null) { + var variable = il.Body.Variables[localIndex.Value]; + var symbols = il.Body.Method.DebugInformation; + if (symbols == null || !symbols.TryGetName(variable, out var variableName)) + return null; + + return (variableName, variable.VariableType); + } + + if (instruction.OpCode.Code == Code.Ret) { + if (instruction.Previous?.Previous?.OpCode.Code == Code.Tail) + return null; + var method = il.Body.Method; + if (method.ReturnsVoid()) + return null; + return ("return", method.ReturnType); + } + + return null; + } + + private void InsertReportValue( + ILProcessor il, + Instruction instruction, + Instruction getValue, + TypeReference valueType, + string valueName, + int line, + FlowMethods flow, + ref int index + ) { + var report = PrepareReportValue(valueType, flow); + if (report == null) + return; + + SafeInsertBeforeAndRetargetAll(il, instruction, getValue); + il.InsertBefore(instruction, valueName != null ? il.Create(OpCodes.Ldstr, valueName) : il.Create(OpCodes.Ldnull)); + il.InsertBefore(instruction, il.CreateLdcI4Best(line)); + il.InsertBefore(instruction, il.CreateCall(report)); + index += 4; + } + + private GenericInstanceMethod? PrepareReportValue(TypeReference valueType, FlowMethods flow) { + if (valueType.IsPointer || valueType.IsFunctionPointer) + return null; + + if (valueType is RequiredModifierType requiredType) + valueType = requiredType.ElementType; // not the same as GetElementType() which unwraps nested ref-types etc + + if (valueType is ByReferenceType byRef) + return PrepareReportValue(byRef.ElementType, flow.ReportRefValue, flow.ReportRefSpanValue, flow.ReportRefReadOnlySpanValue); + + if (!valueType.IsPrimitive && !valueType.IsGenericParameter && valueType.IsValueType) { + var valueTypeDefinition = valueType.Resolve(); + foreach (var attribute in valueTypeDefinition.CustomAttributes) { + // ref structs cannot be reported in a generic way + if (attribute.AttributeType is { Name: nameof(IsByRefLikeAttribute), Namespace: "System.Runtime.CompilerServices" }) + return null; + } + } + + return PrepareReportValue(valueType, flow.ReportValue, flow.ReportSpanValue, flow.ReportReadOnlySpanValue); + } + + private GenericInstanceMethod PrepareReportValue(TypeReference valueType, MethodReference reportAnyNonSpan, MethodReference reportSpan, MethodReference reportReadOnlySpan) { + if (valueType is GenericInstanceType generic) { + if (generic.ElementType.FullName == "System.Span`1") + return new GenericInstanceMethod(reportSpan) { GenericArguments = { generic.GenericArguments[0] } }; + if (generic.ElementType.FullName == "System.ReadOnlySpan`1") + return new GenericInstanceMethod(reportReadOnlySpan) { GenericArguments = { generic.GenericArguments[0] } }; + } + + return new GenericInstanceMethod(reportAnyNonSpan) { GenericArguments = { valueType } }; + } + + private void RewriteExceptionHandlers(ILProcessor il, FlowMethods flow) { + if (!il.Body.HasExceptionHandlers) + return; + + LogILIfEnabled(il, ILLogStep.BeforeRewriteExceptionHandlers); + + var handlers = il.Body.ExceptionHandlers; + for (var i = handlers.Count - 1; i >= 0; i--) { + EnsureTryLeave(handlers[i], i, il); + LogILIfEnabled(il, ILLogStep.AfterEnsureTryLeave, i.ToString()); + } + + for (var i = 0; i < handlers.Count; i++) { + var handler = handlers[i]; + switch (handler.HandlerType) { + case ExceptionHandlerType.Catch: + RewriteCatch(handler.HandlerStart, il, flow); + break; + + case ExceptionHandlerType.Filter: + RewriteCatch(handler.FilterStart, il, flow); + break; + + case ExceptionHandlerType.Finally: + RewriteFinally(handler, ref i, il, flow); + break; + } + } + } + + private void EnsureTryLeave(ExceptionHandler handler, int handlerIndex, ILProcessor il) { + if (handler.TryEnd.Previous.OpCode.Code.IsLeave()) + return; + + // In some cases (e.g. exception throw) handler does + // not end with `leave` -- but we do need it once we wrap + // that throw. + + // If the handler is the last thing in the method. + if (handler.HandlerEnd == null) { + var finalReturn = il.Create(OpCodes.Ret); + il.Append(finalReturn); + handler.HandlerEnd = finalReturn; + } + + var leave = il.Create(OpCodes.Leave, handler.HandlerEnd); + il.InsertBefore(handler.TryEnd, leave); + for (var i = 0; i < handlerIndex; i++) { + il.Body.ExceptionHandlers[i].RetargetAll(handler.TryEnd, leave); + } + } + + private void RewriteCatch(Instruction start, ILProcessor il, FlowMethods flow) { + SafeInsertBeforeAndRetargetAll(il, start, il.Create(OpCodes.Dup)); + il.InsertBefore(start, il.CreateCall(flow.ReportException)); + } + + private void RewriteFinally(ExceptionHandler handler, ref int handlerIndex, ILProcessor il, FlowMethods flow) { + // for try/finally, the only thing we can do is to + // wrap internals of try into a new try+filter+catch + var outerTryLeave = handler.TryEnd.Previous; + + var innerTryLeave = il.Create(OpCodes.Leave_S, outerTryLeave); + var reportCall = il.CreateCall(flow.ReportException); + var catchHandler = il.Create(OpCodes.Pop); + + SafeInsertBeforeAndRetargetAll(il, outerTryLeave, innerTryLeave); + il.InsertBefore(outerTryLeave, reportCall); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Ldc_I4_0)); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Endfilter)); + il.InsertBefore(outerTryLeave, catchHandler); + il.InsertBefore(outerTryLeave, il.Create(OpCodes.Leave_S, outerTryLeave)); + + for (var i = 0; i < handlerIndex; i++) { + il.Body.ExceptionHandlers[i].RetargetAll(outerTryLeave.Next, innerTryLeave.Next); + } + + il.Body.ExceptionHandlers.Insert(handlerIndex, new ExceptionHandler(ExceptionHandlerType.Filter) { + TryStart = handler.TryStart, + TryEnd = reportCall, + FilterStart = reportCall, + HandlerStart = catchHandler, + HandlerEnd = outerTryLeave + }); + handlerIndex += 1; + } + + private bool HasLine([NotNullWhen(true)] SequencePoint? point) { + return point != null && !point.IsHidden; + } + + private static void SafeInsertBeforeAndRetargetAll(ILProcessor il, Instruction target, Instruction instruction) { + var actualTarget = target; + while (actualTarget.Previous?.OpCode.OpCodeType == OpCodeType.Prefix) { + actualTarget = actualTarget.Previous; + } + + il.InsertBefore(actualTarget, instruction); + RetargetAll(il, actualTarget, instruction); + } + + private static void RetargetAll(ILProcessor il, Instruction from, Instruction to) { + foreach (var other in il.Body.Instructions) { + if (other == to) + continue; + + if (other.Operand == from) + other.Operand = to; + } + + if (!il.Body.HasExceptionHandlers) + return; + + foreach (var handler in il.Body.ExceptionHandlers) { + handler.RetargetAll(from, to); + } + } + + private void InsertAfter(ILProcessor il, ref Instruction target, ref int index, Instruction instruction) { + il.InsertAfter(target, instruction); + target = instruction; + index += 1; + } + + private int? GetIndexIfStloc(Instruction instruction) { + switch (instruction.OpCode.Code) { + case Code.Stloc_0: return 0; + case Code.Stloc_1: return 1; + case Code.Stloc_2: return 2; + case Code.Stloc_3: return 3; + + case Code.Stloc_S: + case Code.Stloc: + return ((VariableReference)instruction.Operand).Index; + + default: return null; + } + } + + [Conditional("DEBUG")] + private void LogILIfEnabled(ILProcessor il, ILLogStep step, string? subStepName = null) { + #if DEBUG + if (!DiagnosticLog.IsEnabled()) + return; + + var builder = new StringBuilder(); + var indent = 0; + foreach (var instruction in il.Body.Instructions) { + foreach (var handler in il.Body.ExceptionHandlers) { + if (handler.TryStart == instruction) { + builder.Append(new string(' ', indent)); + builder.AppendLine(".try {"); + indent += 4; + } + else if (handler.TryEnd == instruction) { + indent -= 4; + builder.Append(new string(' ', indent)); + builder.AppendLine("}"); + } + + if (handler.HandlerStart == instruction) { + builder.Append(new string(' ', indent)); + builder.AppendLine(handler.HandlerType switch { + ExceptionHandlerType.Catch => ".catch {", + ExceptionHandlerType.Finally => ".finally {", + ExceptionHandlerType.Filter => ".filter {", + ExceptionHandlerType.Fault => ".fault {", + _ => throw new() + }); + indent += 4; + } + else if (handler.HandlerEnd == instruction) { + indent -= 4; + builder.Append(new string(' ', indent)); + builder.AppendLine("}"); + } + } + + builder.Append(new string(' ', indent)); + builder.AppendLine(instruction.ToString()); + } + DiagnosticLog.LogText( + $"Flow.IL.{il.Body.Method.Name}.{step:D}.{step:G}{(subStepName != null ? "." + subStepName : "")}", + builder.ToString() + ); + #endif + } + + private enum ILLogStep { + Initial = 1, + AfterReportJump, + BeforeRewriteExceptionHandlers, + AfterEnsureTryLeave, + Final + } + + private struct FlowMethods { + public MethodReference ReportMethodArea { get; set; } + public MethodReference ReportLoopArea { get; set; } + public MethodReference ReportLineStart { get; set; } + public MethodReference ReportJump { get; set; } + public MethodReference ReportValue { get; set; } + public MethodReference ReportRefValue { get; set; } + public MethodReference ReportSpanValue { get; set; } + public MethodReference ReportRefSpanValue { get; set; } + public MethodReference ReportReadOnlySpanValue { get; set; } + public MethodReference ReportRefReadOnlySpanValue { get; set; } + public MethodReference ReportException { get; set; } + } + } +} diff --git a/source/Server/Execution/Internal/IAssemblyRewriter.cs b/source/Server/Execution/Internal/IAssemblyRewriter.cs new file mode 100644 index 000000000..14ff3b471 --- /dev/null +++ b/source/Server/Execution/Internal/IAssemblyRewriter.cs @@ -0,0 +1,8 @@ +using MirrorSharp.Advanced; +using Mono.Cecil; + +namespace SharpLab.Server.Execution.Internal { + public interface IAssemblyRewriter { + void Rewrite(ModuleDefinition module, IWorkSession session); + } +} diff --git a/source/Server/Execution/Internal/IAssemblyStreamRewriterComposer.cs b/source/Server/Execution/Internal/IAssemblyStreamRewriterComposer.cs new file mode 100644 index 000000000..e0a508e9b --- /dev/null +++ b/source/Server/Execution/Internal/IAssemblyStreamRewriterComposer.cs @@ -0,0 +1,8 @@ +using MirrorSharp.Advanced; +using SharpLab.Server.Common; + +namespace SharpLab.Server.Execution.Internal { + public interface IAssemblyStreamRewriterComposer { + AssemblyStreamRewriteResult Rewrite(CompilationStreamPair streams, IWorkSession session); + } +} \ No newline at end of file diff --git a/source/Server/Execution/Internal/IContainerAssemblyRewriter.cs b/source/Server/Execution/Internal/IContainerAssemblyRewriter.cs deleted file mode 100644 index a49f4aa27..000000000 --- a/source/Server/Execution/Internal/IContainerAssemblyRewriter.cs +++ /dev/null @@ -1,8 +0,0 @@ -using MirrorSharp.Advanced; -using Mono.Cecil; - -namespace SharpLab.Server.Execution.Internal { - public interface IContainerAssemblyRewriter { - void Rewrite(AssemblyDefinition assembly, IWorkSession session); - } -} diff --git a/source/Server/Execution/Internal/MemoryGraphArgumentNamesRewriter.cs b/source/Server/Execution/Internal/MemoryGraphArgumentNamesRewriter.cs index ee8a2ee6f..1c241dd07 100644 --- a/source/Server/Execution/Internal/MemoryGraphArgumentNamesRewriter.cs +++ b/source/Server/Execution/Internal/MemoryGraphArgumentNamesRewriter.cs @@ -8,7 +8,7 @@ using SharpLab.Server.Common; namespace SharpLab.Server.Execution.Internal { - public class MemoryGraphArgumentNamesRewriter : IContainerAssemblyRewriter { + public class MemoryGraphArgumentNamesRewriter : IAssemblyRewriter { private readonly IReadOnlyDictionary _languages; private static readonly MethodInfo AllocateNextMethod = @@ -20,23 +20,28 @@ public MemoryGraphArgumentNamesRewriter(IReadOnlyList language _languages = languages.ToDictionary(l => l.LanguageName); } - public void Rewrite(AssemblyDefinition assembly, IWorkSession session) { - foreach (var module in assembly.Modules) { - var argumentMethods = new ArgumentMethods { - AllocateNext = module.ImportReference(AllocateNextMethod), - AddToNext = module.ImportReference(AddToNextMethod) - }; - - foreach (var type in module.Types) { - Rewrite(type, session, argumentMethods); - foreach (var nested in type.NestedTypes) { - Rewrite(nested, session, argumentMethods); - } + public void Rewrite(ModuleDefinition module, IWorkSession session) { + if (!module.HasTypes) + return; + + var argumentMethods = new ArgumentMethods { + AllocateNext = module.ImportReference(AllocateNextMethod), + AddToNext = module.ImportReference(AddToNextMethod) + }; + + foreach (var type in module.Types) { + Rewrite(type, session, argumentMethods); + if (!type.HasNestedTypes) + continue; + foreach (var nested in type.NestedTypes) { + Rewrite(nested, session, argumentMethods); } } - } + } private void Rewrite(TypeDefinition type, IWorkSession session, ArgumentMethods argumentMethods) { + if (!type.HasMethods) + return; foreach (var method in type.Methods) { Rewrite(method, session, argumentMethods); } diff --git a/source/Server/Explanation/ExplanationModule.cs b/source/Server/Explanation/ExplanationModule.cs index dd1c0a83e..5b0e10491 100644 --- a/source/Server/Explanation/ExplanationModule.cs +++ b/source/Server/Explanation/ExplanationModule.cs @@ -22,9 +22,14 @@ protected override void Load(ContainerBuilder builder) { builder.Register(c => { var configuration = c.Resolve(); + return new ExternalSyntaxExplanationSettings( - configuration.GetValue("App:Explanations:Urls:CSharp"), - configuration.GetValue("App:Explanations:UpdatePeriod") + // TODO: Theoretically this needs a helper, but I am looking to deprecate explanations + // feature anyways. + configuration.GetValue("App:Explanations:Urls:CSharp") + ?? throw new ("Setting 'App:Explanations:Urls:CSharp' was not found"), + configuration.GetValue("App:Explanations:UpdatePeriod") + ?? throw new("Setting 'App:Explanations:UpdatePeriod' was not found") ); }).SingleInstance(); } diff --git a/source/Server/Explanation/Internal/ExternalSyntaxExplanationProvider.cs b/source/Server/Explanation/Internal/ExternalSyntaxExplanationProvider.cs index 68b86b1df..60938dacf 100644 --- a/source/Server/Explanation/Internal/ExternalSyntaxExplanationProvider.cs +++ b/source/Server/Explanation/Internal/ExternalSyntaxExplanationProvider.cs @@ -3,131 +3,130 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using SharpLab.Server.Monitoring; using SharpYaml.Serialization; using SourcePath; using SourcePath.Roslyn; -using SharpLab.Server.Monitoring; - -namespace SharpLab.Server.Explanation.Internal { - public class ExternalSyntaxExplanationProvider : ISyntaxExplanationProvider, IDisposable { - private readonly Func _httpClientFactory; - private readonly ExternalSyntaxExplanationSettings _settings; - private IReadOnlyCollection? _explanations; - private readonly SemaphoreSlim _explanationsLock = new(1); +namespace SharpLab.Server.Explanation.Internal; +public class ExternalSyntaxExplanationProvider : ISyntaxExplanationProvider, IDisposable { + private readonly Func _httpClientFactory; + private readonly ExternalSyntaxExplanationSettings _settings; - private Task? _updateTask; - private CancellationTokenSource? _updateCancellationSource; + private IReadOnlyCollection? _explanations; + private readonly SemaphoreSlim _explanationsLock = new(1); - private readonly Serializer _serilializer = new (new() { - NamingConvention = new FlatNamingConvention() - }); - private readonly IMonitor _monitor; - private readonly ISourcePathParser _sourcePathParser; - - public ExternalSyntaxExplanationProvider( - Func httpClientFactory, - ExternalSyntaxExplanationSettings settings, - ISourcePathParser sourcePathParser, - IMonitor monitor - ) { - _httpClientFactory = httpClientFactory; - _settings = settings; - _sourcePathParser = sourcePathParser; - _monitor = monitor; - } + private Task? _updateTask; + private CancellationTokenSource? _updateCancellationSource; - public async ValueTask> GetExplanationsAsync(CancellationToken cancellationToken) { - if (_explanations == null) { - try { - await _explanationsLock.WaitAsync(cancellationToken).ConfigureAwait(false); - if (_explanations != null) - return _explanations; - _explanations = await LoadExplanationsSlowAsync(cancellationToken).ConfigureAwait(false); - _updateCancellationSource = new CancellationTokenSource(); - _updateTask = Task.Run(UpdateLoopAsync); - } - finally { - _explanationsLock.Release(); - } - } + private readonly Serializer _serilializer = new (new() { + NamingConvention = new FlatNamingConvention() + }); + private readonly IMonitor _monitor; + private readonly ISourcePathParser _sourcePathParser; - return _explanations; - } - - private async Task> LoadExplanationsSlowAsync(CancellationToken cancellationToken) { - var explanations = new List(); - var serializer = new Serializer(); - using (var client = _httpClientFactory()) { - var response = await client.GetAsync(_settings.SourceUrl, cancellationToken).ConfigureAwait(false); - response.EnsureSuccessStatusCode(); - - var yamlString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - var yaml = _serilializer.Deserialize>(yamlString); - foreach (var item in yaml) { - SyntaxExplanation parsed; - try { - parsed = ParseExplanation(item); - } - catch (Exception ex) { - // depending on SourcePath version, it's possible that - // an explanation fails to parse on some branches - _monitor.Exception(ex, session: null); - continue; - } - explanations.Add(parsed); - } - } - return explanations; - } + public ExternalSyntaxExplanationProvider( + Func httpClientFactory, + ExternalSyntaxExplanationSettings settings, + ISourcePathParser sourcePathParser, + IMonitor monitor + ) { + _httpClientFactory = httpClientFactory; + _settings = settings; + _sourcePathParser = sourcePathParser; + _monitor = monitor; + } - private SyntaxExplanation ParseExplanation(YamlExplanation item) { - ISourcePath path; + public async ValueTask> GetExplanationsAsync(CancellationToken cancellationToken) { + if (_explanations == null) { try { - path = _sourcePathParser.Parse(item.Path); + await _explanationsLock.WaitAsync(cancellationToken).ConfigureAwait(false); + if (_explanations != null) + return _explanations; + _explanations = await LoadExplanationsSlowAsync(cancellationToken).ConfigureAwait(false); + _updateCancellationSource = new CancellationTokenSource(); + _updateTask = Task.Run(UpdateLoopAsync); } - catch (Exception ex) { - throw new Exception($"Failed to parse path for '{item.Name}': {ex.Message}.", ex); + finally { + _explanationsLock.Release(); } - return new SyntaxExplanation(path, item.Name!, item.Text!, item.Link!); } - private async Task UpdateLoopAsync() { - while (!_updateCancellationSource!.IsCancellationRequested) { - try { - await Task.Delay(_settings.UpdatePeriod, _updateCancellationSource.Token).ConfigureAwait(false); - } - catch (TaskCanceledException) { - return; - } + return _explanations; + } + + private async Task> LoadExplanationsSlowAsync(CancellationToken cancellationToken) { + var explanations = new List(); + var serializer = new Serializer(); + using (var client = _httpClientFactory()) { + var response = await client.GetAsync(_settings.SourceUrl, cancellationToken).ConfigureAwait(false); + response.EnsureSuccessStatusCode(); + + var yamlString = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + var yaml = _serilializer.Deserialize>(yamlString); + foreach (var item in yaml) { + SyntaxExplanation parsed; try { - _explanations = await LoadExplanationsSlowAsync(_updateCancellationSource.Token).ConfigureAwait(false); + parsed = ParseExplanation(item); } catch (Exception ex) { + // depending on SourcePath version, it's possible that + // an explanation fails to parse on some branches _monitor.Exception(ex, session: null); - // intentionally not re-throwing -- retrying after delay + continue; } + explanations.Add(parsed); } } + return explanations; + } - public void Dispose() { - DisposeAsync().Wait(TimeSpan.FromMinutes(1)); + private SyntaxExplanation ParseExplanation(YamlExplanation item) { + ISourcePath path; + try { + path = _sourcePathParser.Parse(item.Path); } + catch (Exception ex) { + throw new Exception($"Failed to parse path for '{item.Name}': {ex.Message}.", ex); + } + return new SyntaxExplanation(path, item.Name!, item.Text!, item.Link!); + } - public async Task DisposeAsync() { - using (_updateCancellationSource) { - if (_updateTask == null) - return; - _updateCancellationSource!.Cancel(); - await _updateTask.ConfigureAwait(true); + private async Task UpdateLoopAsync() { + while (!_updateCancellationSource!.IsCancellationRequested) { + try { + await Task.Delay(_settings.UpdatePeriod, _updateCancellationSource.Token).ConfigureAwait(false); + } + catch (TaskCanceledException) { + return; + } + try { + _explanations = await LoadExplanationsSlowAsync(_updateCancellationSource.Token).ConfigureAwait(false); + } + catch (Exception ex) { + _monitor.Exception(ex, session: null); + // intentionally not re-throwing -- retrying after delay } } + } - private class YamlExplanation { - public string? Name { get; set; } - public string? Text { get; set; } - public string? Link { get; set; } - public string? Path { get; set; } + public void Dispose() { + DisposeAsync().Wait(TimeSpan.FromMinutes(1)); + } + + public async Task DisposeAsync() { + using (_updateCancellationSource) { + if (_updateTask == null) + return; + _updateCancellationSource!.Cancel(); + await _updateTask.ConfigureAwait(true); } } + + private class YamlExplanation { + public string? Name { get; set; } + public string? Text { get; set; } + public string? Link { get; set; } + public string? Path { get; set; } + } } diff --git a/source/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs b/source/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs new file mode 100644 index 000000000..2ca9d175a --- /dev/null +++ b/source/Server/Integration/Azure/ApplicationInsightsMetricMonitor.cs @@ -0,0 +1,22 @@ +using Microsoft.ApplicationInsights; +using SharpLab.Server.Monitoring; + +namespace SharpLab.Server.Integration.Azure; + +public class ApplicationInsightsMetricMonitor : IZeroDimensionMetricMonitor, IOneDimensionMetricMonitor { + private readonly Metric _metric; + + public ApplicationInsightsMetricMonitor(Metric metric) { + Argument.NotNull(nameof(metric), metric); + + _metric = metric; + } + + public void Track(double value) { + _metric.TrackValue(value); + } + + public void Track(string dimension, double value) { + _metric.TrackValue(value, dimension); + } +} \ No newline at end of file diff --git a/source/Server/Integration/Azure/ApplicationInsightsMonitor.cs b/source/Server/Integration/Azure/ApplicationInsightsMonitor.cs index b42b24123..ad3415687 100644 --- a/source/Server/Integration/Azure/ApplicationInsightsMonitor.cs +++ b/source/Server/Integration/Azure/ApplicationInsightsMonitor.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using Microsoft.ApplicationInsights; @@ -11,68 +10,74 @@ using SharpLab.Server.MirrorSharp; using SharpLab.Server.Monitoring; -namespace SharpLab.Server.Integration.Azure { - public class ApplicationInsightsMonitor : IMonitor { - private static readonly ConcurrentDictionary _metricIdentifiers = new(); +namespace SharpLab.Server.Integration.Azure; - private readonly TelemetryClient _client; - private readonly string _webAppName; +public class ApplicationInsightsMonitor : IMonitor { + private readonly TelemetryClient _client; + private readonly string _webAppName; + private readonly Func _createMetricMonitor; - public ApplicationInsightsMonitor(TelemetryClient client, string webAppName) { - _client = Argument.NotNull(nameof(client), client); - _webAppName = Argument.NotNullOrEmpty(nameof(webAppName), webAppName); - } + public ApplicationInsightsMonitor(TelemetryClient client, string webAppName, Func createMetricMonitor) { + _client = Argument.NotNull(nameof(client), client); + _webAppName = Argument.NotNullOrEmpty(nameof(webAppName), webAppName); + _createMetricMonitor = Argument.NotNull(nameof(createMetricMonitor), createMetricMonitor); + } - public void Metric(MonitorMetric metric, double value) { - var identifier = _metricIdentifiers.GetOrAdd(metric, static m => new(m.Namespace, m.Name)); - _client.GetMetric(identifier).TrackValue(value); - } + public IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name) + => MetricSlowInternal(new (@namespace, name)); + + public IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension) + => MetricSlowInternal(new (@namespace, name, dimension)); + + private ApplicationInsightsMetricMonitor MetricSlowInternal(MetricIdentifier identifier) { + var metric = _client.GetMetric(identifier); + return _createMetricMonitor(metric); + } - public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { - var sessionInternals = session as WorkSession; - var telemetry = new ExceptionTelemetry(exception) { - Context = { Session = { Id = session?.GetSessionId() } }, - Properties = { - { "Web App", _webAppName }, - { "Code", session?.GetText() }, - { "Language", session?.LanguageName }, - { "Target", session?.GetTargetName() }, - { "Cursor", sessionInternals?.CursorPosition.ToString() }, - { "Completion", FormatCompletion(sessionInternals) } - } - }; - if (extras != null) { - foreach (var pair in extras) { - telemetry.Properties.Add(pair.Key, pair.Value); - } + public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { + var sessionInternals = session as WorkSession; + var telemetry = new ExceptionTelemetry(exception) { + Context = { Session = { Id = session?.GetSessionId() } }, + Properties = { + { "Web App", _webAppName }, + { "Code", session?.GetText() }, + { "Language", session?.LanguageName }, + { "Target", session?.GetTargetName() }, + { "Cursor", sessionInternals?.CursorPosition.ToString() }, + { "Completion", FormatCompletion(sessionInternals) } + } + }; + if (extras != null) { + foreach (var pair in extras) { + telemetry.Properties.Add(pair.Key, pair.Value); } - _client.TrackException(telemetry); } + _client.TrackException(telemetry); + } - private string? FormatCompletion(WorkSession? session) { - try { - if (session == null) - return null; + private string? FormatCompletion(WorkSession? session) { + try { + if (session == null) + return null; - var current = session.CurrentCompletion; - if (current.List == null && !current.ChangeEchoPending && current.PendingChar == null) - return null; + var current = session.CurrentCompletion; + if (current.List == null && !current.ChangeEchoPending && current.PendingChar == null) + return null; - return JsonConvert.ToString(new { - List = current.List is { } list ? new { - Items = new { - Take10 = list.Items.Take(10), - Length = list.Items.Length - }, - list.Span - } : null, - current.ChangeEchoPending, - current.PendingChar - }); - } - catch (Exception ex) { - return ""; - } + return JsonConvert.ToString(new { + List = current.List is { } list ? new { + Items = new { + Take10 = list.ItemsList.Take(10), + list.ItemsList.Count + }, + list.Span + } : null, + current.ChangeEchoPending, + current.PendingChar + }); + } + catch (Exception ex) { + return ""; } } } diff --git a/source/Server/Integration/Azure/AzureBlobResultCacheStore.cs b/source/Server/Integration/Azure/AzureBlobResultCacheStore.cs index a66663725..d9ffe8dfe 100644 --- a/source/Server/Integration/Azure/AzureBlobResultCacheStore.cs +++ b/source/Server/Integration/Azure/AzureBlobResultCacheStore.cs @@ -5,57 +5,55 @@ using Azure.Storage.Blobs; using SharpLab.Server.Caching.Internal; using System; -using SharpLab.Server.Monitoring; using SharpLab.Server.Caching; -namespace SharpLab.Server.Integration.Azure { - public class AzureBlobResultCacheStore : IResultCacheStore, IDisposable { - private readonly MemoryCache _alreadyCached = new(new MemoryCacheOptions()); - private readonly BlobContainerClient _containerClient; - private readonly string _cachePathPrefix; - private readonly IMonitor _monitor; - - public AzureBlobResultCacheStore( - BlobContainerClient containerClient, - string cachePathPrefix, - IMonitor monitor - ) { - _containerClient = containerClient; - _cachePathPrefix = cachePathPrefix; - _monitor = monitor; - } +namespace SharpLab.Server.Integration.Azure; +public class AzureBlobResultCacheStore : IResultCacheStore, IDisposable { + private readonly MemoryCache _alreadyCached = new(new MemoryCacheOptions()); + private readonly BlobContainerClient _containerClient; + private readonly string _cachePathPrefix; + private readonly ICachingTracker _cachingTracker; + + public AzureBlobResultCacheStore( + BlobContainerClient containerClient, + string cachePathPrefix, + ICachingTracker cachingTracker + ) { + _containerClient = containerClient; + _cachePathPrefix = cachePathPrefix; + _cachingTracker = cachingTracker; + } - public Task StoreAsync(string key, Stream stream, CancellationToken cancellationToken) { - Argument.NotNullOrEmpty(nameof(key), key); - Argument.NotNull(nameof(stream), stream); - - // no need to retry if we already processed this one - if (_alreadyCached.TryGetValue(key, out _)) - return Task.CompletedTask; - - // it's OK to do this before trying, if we failed before we don't want to retry either - var currentCall = new object(); - if (_alreadyCached.GetOrCreate(key, e => Cache(e, currentCall)) != currentCall) - return Task.CompletedTask; - - _monitor.Metric(CachingMetrics.BlobUploadRequestCount, 1); - var path = $"{_cachePathPrefix}/{key}.json"; - try { - return _containerClient.UploadBlobAsync(path, stream, cancellationToken); - } - catch { - _monitor.Metric(CachingMetrics.BlobUploadErrorCount, 1); - throw; - } - } + public Task StoreAsync(string key, Stream stream, CancellationToken cancellationToken) { + Argument.NotNullOrEmpty(nameof(key), key); + Argument.NotNull(nameof(stream), stream); - private object Cache(ICacheEntry entry, object value) { - entry.SlidingExpiration = TimeSpan.FromDays(1); - return value; - } + // no need to retry if we already processed this one + if (_alreadyCached.TryGetValue(key, out _)) + return Task.CompletedTask; + + // it's OK to do this before trying, if we failed before we don't want to retry either + var currentCall = new object(); + if (_alreadyCached.GetOrCreate(key, e => Cache(e, currentCall)) != currentCall) + return Task.CompletedTask; - public void Dispose() { - _alreadyCached.Dispose(); + _cachingTracker.TrackBlobUploadRequest(); + var path = $"{_cachePathPrefix}/{key}.json"; + try { + return _containerClient.UploadBlobAsync(path, stream, cancellationToken); } + catch { + _cachingTracker.TrackBlobUploadError(); + throw; + } + } + + private object Cache(ICacheEntry entry, object value) { + entry.SlidingExpiration = TimeSpan.FromDays(1); + return value; + } + + public void Dispose() { + _alreadyCached.Dispose(); } } diff --git a/source/Server/Integration/Azure/AzureModule.cs b/source/Server/Integration/Azure/AzureModule.cs index 399c718d1..8a2220fcd 100644 --- a/source/Server/Integration/Azure/AzureModule.cs +++ b/source/Server/Integration/Azure/AzureModule.cs @@ -12,88 +12,92 @@ using SharpLab.Server.Common; using SharpLab.Server.Monitoring; -namespace SharpLab.Server.Integration.Azure { - [UsedImplicitly] - public class AzureModule : Module { - protected override void Load(ContainerBuilder builder) { - // This is available even on local (through a mock) - RegisterCacheStore(builder); +namespace SharpLab.Server.Integration.Azure; - var keyVaultUrl = Environment.GetEnvironmentVariable("SHARPLAB_KEY_VAULT_URL"); - if (keyVaultUrl == null) - return; +[UsedImplicitly] +public class AzureModule : Module { + protected override void Load(ContainerBuilder builder) { + // This is available even on local (through a mock) + RegisterCacheStore(builder); - RegisterKeyVault(builder, keyVaultUrl); - RegisterTableStorage(builder); - RegisterApplicationInsights(builder); - } + var keyVaultUrl = Environment.GetEnvironmentVariable("SHARPLAB_KEY_VAULT_URL"); + if (keyVaultUrl == null) + return; - private void RegisterCacheStore(ContainerBuilder builder) { - const string cacheClientName = "BlobContainerClient-CacheClient"; - var cachePathPrefix = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_CACHE_PATH_PREFIX"); + RegisterKeyVault(builder, keyVaultUrl); + RegisterTableStorage(builder); + RegisterApplicationInsights(builder); + } + + private void RegisterCacheStore(ContainerBuilder builder) { + const string cacheClientName = "BlobContainerClient-CacheClient"; + var cachePathPrefix = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_CACHE_PATH_PREFIX"); + + builder + .Register(c => { + var connectionString = c.Resolve().GetSecret("PublicStorageConnectionString"); + return new BlobContainerClient(connectionString, "cache"); + }) + .Named(cacheClientName) + .SingleInstance(); - builder - .Register(c => { - var connectionString = c.Resolve().GetSecret("PublicStorageConnectionString"); - return new BlobContainerClient(connectionString, "cache"); - }) - .Named(cacheClientName) - .SingleInstance(); + builder + .RegisterType() + .As() + .SingleInstance() + .WithParameter("cachePathPrefix", cachePathPrefix) + .WithParameter(new ResolvedParameter( + (p, c) => p.ParameterType == typeof(BlobContainerClient), + (p, c) => c.ResolveNamed(cacheClientName) + )); + } - builder - .RegisterType() - .As() - .SingleInstance() - .WithParameter("cachePathPrefix", cachePathPrefix) - .WithParameter(new ResolvedParameter( - (p, c) => p.ParameterType == typeof(BlobContainerClient), - (p, c) => c.ResolveNamed(cacheClientName) - )); - } + private void RegisterKeyVault(ContainerBuilder builder, string keyVaultUrl) { + var secretClient = new SecretClient(new Uri(keyVaultUrl), new ManagedIdentityCredential()); + builder.RegisterInstance(secretClient) + .AsSelf(); - private void RegisterKeyVault(ContainerBuilder builder, string keyVaultUrl) { - var secretClient = new SecretClient(new Uri(keyVaultUrl), new ManagedIdentityCredential()); - builder.RegisterInstance(secretClient) - .AsSelf(); + builder.RegisterType() + .As() + .SingleInstance(); + } - builder.RegisterType() - .As() - .SingleInstance(); - } + private void RegisterTableStorage(ContainerBuilder builder) { + builder.Register(c => { + var connectionString = c.Resolve().GetSecret("StorageConnectionString"); + return CloudStorageAccount.Parse(connectionString).CreateCloudTableClient(); + }).AsSelf() + .SingleInstance(); - private void RegisterTableStorage(ContainerBuilder builder) { - builder.Register(c => { - var connectionString = c.Resolve().GetSecret("StorageConnectionString"); - return CloudStorageAccount.Parse(connectionString).CreateCloudTableClient(); - }).AsSelf() - .SingleInstance(); + builder.RegisterType() + .As() + .AsSelf() + .WithParameter("flagKeys", new[] { "ContainerExperimentRollout" }) + .WithParameter(new ResolvedParameter( + (p, _) => p.ParameterType == typeof(CloudTable), + (_, c) => c.Resolve().GetTableReference("featureflags") + )) + .SingleInstance(); - builder.RegisterType() - .As() - .AsSelf() - .WithParameter("flagKeys", new[] { "ContainerExperimentRollout" }) - .WithParameter(new ResolvedParameter( - (p, _) => p.ParameterType == typeof(CloudTable), - (_, c) => c.Resolve().GetTableReference("featureflags") - )) - .SingleInstance(); + builder.RegisterBuildCallback(c => c.Resolve().Start()); + } - builder.RegisterBuildCallback(c => c.Resolve().Start()); - } + private void RegisterApplicationInsights(ContainerBuilder builder) { + builder.Register(c => { + var connectionString = c.Resolve().GetSecret("AppInsightsConnectionString"); + var configuration = new TelemetryConfiguration { ConnectionString = connectionString }; + return new TelemetryClient(configuration); + }).AsSelf() + .SingleInstance(); - private void RegisterApplicationInsights(ContainerBuilder builder) { - builder.Register(c => { - var instrumentationKey = c.Resolve().GetSecret("AppInsightsInstrumentationKey"); - var configuration = new TelemetryConfiguration { InstrumentationKey = instrumentationKey }; - return new TelemetryClient(configuration); - }).AsSelf() - .SingleInstance(); + builder.RegisterType() + .AsSelf() + .InstancePerDependency(); - var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); - builder.RegisterType() - .As() - .WithParameter("webAppName", webAppName) - .SingleInstance(); - } + var webAppName = EnvironmentHelper.GetRequiredEnvironmentVariable("SHARPLAB_WEBAPP_NAME"); + builder.RegisterType() + .As() + .WithParameter("webAppName", webAppName) + .SingleInstance(); } } \ No newline at end of file diff --git a/source/Server/Integration/Azure/KeyVaultSecretsClient.cs b/source/Server/Integration/Azure/KeyVaultSecretsClient.cs index f99b4e220..eeaea9c81 100644 --- a/source/Server/Integration/Azure/KeyVaultSecretsClient.cs +++ b/source/Server/Integration/Azure/KeyVaultSecretsClient.cs @@ -1,16 +1,16 @@ using Azure.Security.KeyVault.Secrets; using SharpLab.Server.Common; -namespace SharpLab.Server.Integration.Azure { - public class KeyVaultSecretsClient : ISecretsClient { - private readonly SecretClient _secretClient; +namespace SharpLab.Server.Integration.Azure; - public KeyVaultSecretsClient(SecretClient secretClient) { - _secretClient = secretClient; - } +public class KeyVaultSecretsClient : ISecretsClient { + private readonly SecretClient _secretClient; - public string GetSecret(string key) { - return _secretClient.GetSecret(key).Value.Value; - } + public KeyVaultSecretsClient(SecretClient secretClient) { + _secretClient = secretClient; + } + + public string GetSecret(string key) { + return _secretClient.GetSecret(key).Value.Value; } } diff --git a/source/Server/MirrorSharp/ConnectionSendViewer.cs b/source/Server/MirrorSharp/ConnectionSendViewer.cs index 116e8e774..da298f9e5 100644 --- a/source/Server/MirrorSharp/ConnectionSendViewer.cs +++ b/source/Server/MirrorSharp/ConnectionSendViewer.cs @@ -5,59 +5,57 @@ using MirrorSharp.Advanced.EarlyAccess; using SharpLab.Server.Caching; using SharpLab.Server.Execution; -using SharpLab.Server.Monitoring; - -namespace SharpLab.Server.MirrorSharp { - public class ConnectionSendViewer : IConnectionSendViewer { - private readonly IResultCacher _cacher; - private readonly IExceptionLogger _exceptionLogger; - private readonly IMonitor _monitor; - - public ConnectionSendViewer(IResultCacher cacher, IExceptionLogger exceptionLogger, IMonitor monitor) { - _cacher = cacher; - _exceptionLogger = exceptionLogger; - _monitor = monitor; - } - public Task ViewDuringSendAsync(string messageTypeName, ReadOnlyMemory message, IWorkSession session, CancellationToken cancellationToken) { - if (messageTypeName != "slowUpdate") - return Task.CompletedTask; +namespace SharpLab.Server.MirrorSharp; +public class ConnectionSendViewer : IConnectionSendViewer { + private readonly IResultCacher _cacher; + private readonly IExceptionLogger _exceptionLogger; + private readonly ICachingTracker _tracker; - if (session.HasCachingSeenSlowUpdateBefore()) - return Task.CompletedTask; + public ConnectionSendViewer(IResultCacher cacher, IExceptionLogger exceptionLogger, ICachingTracker tracker) { + _cacher = cacher; + _exceptionLogger = exceptionLogger; + _tracker = tracker; + } - // if update should not be cached, we will still not want to cache or measure the next one - session.SetCachingHasSeenSlowUpdate(); + public Task ViewDuringSendAsync(string messageTypeName, ReadOnlyMemory message, IWorkSession session, CancellationToken cancellationToken) { + if (messageTypeName != "slowUpdate") + return Task.CompletedTask; - if (session.IsCachingDisabled()) { - _monitor.Metric(CachingMetrics.NoCacheRequestCount, 1); - return Task.CompletedTask; - } + if (session.HasCachingSeenSlowUpdateBefore()) + return Task.CompletedTask; - if (!ShouldCache(session.GetLastSlowUpdateResult())) - return Task.CompletedTask; + // if update should not be cached, we will still not want to cache or measure the next one + session.SetCachingHasSeenSlowUpdate(); - _monitor.Metric(CachingMetrics.CacheableRequestCount, 1); - return SafeCacheAsync(message, session, cancellationToken); + if (session.IsCachingDisabled()) { + _tracker.TrackNoCacheRequest(); + return Task.CompletedTask; } - private bool ShouldCache(object? result) { - return result is not ContainerExecutionResult { OutputFailed: true }; - } + if (!ShouldCache(session.GetLastSlowUpdateResult())) + return Task.CompletedTask; + + _tracker.TrackCacheableRequest(); + return SafeCacheAsync(message, session, cancellationToken); + } + + private bool ShouldCache(object? result) { + return result is not ContainerExecutionResult { OutputFailed: true }; + } - private async Task SafeCacheAsync(ReadOnlyMemory message, IWorkSession session, CancellationToken cancellationToken) { - try { - var key = new ResultCacheKeyData( - session.LanguageName, - session.GetTargetName()!, - session.GetOptimize()!, - session.GetText() - ); - await _cacher.CacheAsync(key, message, cancellationToken); - } - catch (Exception ex) { - _exceptionLogger.LogException(ex, session); - } + private async Task SafeCacheAsync(ReadOnlyMemory message, IWorkSession session, CancellationToken cancellationToken) { + try { + var key = new ResultCacheKeyData( + session.LanguageName, + session.GetTargetName()!, + session.GetOptimize()!, + session.GetText() + ); + await _cacher.CacheAsync(key, message, cancellationToken); + } + catch (Exception ex) { + _exceptionLogger.LogException(ex, session); } } } diff --git a/source/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs b/source/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs index 36044b473..becd49482 100644 --- a/source/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs +++ b/source/Server/MirrorSharp/Guards/CSharpCompilationGuard.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using MirrorSharp.Advanced.EarlyAccess; @@ -11,17 +13,51 @@ public void ValidateCompilation(CSharpCompilation compilation) { if (!tree.TryGetRoot(out var root)) throw new InvalidOperationException(); - foreach (var qualified in root.DescendantNodes(n => !(n is QualifiedNameSyntax)).OfType()) { + foreach (var qualified in ShallowDescendantsOfType(root)) { if (qualified is { Left: QualifiedNameSyntax { Left: QualifiedNameSyntax { Left: QualifiedNameSyntax _ } } }) throw new RoslynCompilationGuardException("Reference exceeded type nesting limit: " + qualified); } - foreach (var generic in root.DescendantNodes().OfType()) { + foreach (var generic in ShallowDescendantsOfType(root)) { if (generic.Parameters.Count > 4) throw new RoslynCompilationGuardException("Generic parameter list exceeded size limit: " + generic); } + foreach (var generic in ShallowDescendantsOfType(root)) { + if (GetTotalGenericArgumentCount(generic) > 5) + throw new RoslynCompilationGuardException("Generic argument list exceeded size limit: " + generic); + } + + foreach (var type in ShallowDescendantsOfType(root)) { + EnsureNoRecursiveGenericPointerAttributes(type); + } } } + + private int GetTotalGenericArgumentCount(TypeArgumentListSyntax generic) { + var count = 0; + foreach (var subgeneric in generic.DescendantNodesAndSelf().OfType()) { + count += subgeneric.Arguments.Count; + } + return count; + } + + private void EnsureNoRecursiveGenericPointerAttributes(TypeDeclarationSyntax type) { + if (type.TypeParameterList == null) + return; + + foreach (var attribute in ShallowDescendantsOfType(type)) { + foreach (var typeArgumentList in ShallowDescendantsOfType(attribute)) { + foreach (var functionPointer in ShallowDescendantsOfType(typeArgumentList)) { + throw new RoslynCompilationGuardException("Specific use of pointer type in generics is not allowed due to high chance of application failure (see https://github.com/dotnet/roslyn/issues/65594): " + functionPointer); + } + } + } + } + + private IEnumerable ShallowDescendantsOfType(SyntaxNode node) + where TSyntaxNode : SyntaxNode { + return node.DescendantNodes(static n => n is not TSyntaxNode).OfType(); + } } } diff --git a/source/Server/MirrorSharp/Guards/RoslynSourceTextGuard.cs b/source/Server/MirrorSharp/Guards/RoslynSourceTextGuard.cs index 9ebabbf04..79b16f0e0 100644 --- a/source/Server/MirrorSharp/Guards/RoslynSourceTextGuard.cs +++ b/source/Server/MirrorSharp/Guards/RoslynSourceTextGuard.cs @@ -31,14 +31,26 @@ private class ValidatingSourceTextWriter : TextWriter { private int _squareBracketsNestingLevel; private readonly int[] _squareBracketsAdjacentPairCounts = new int[BracketsNestingLimit + 1]; + private bool _allowNextTopLevelAdjacentSquareBrackets = true; + public override Encoding Encoding => Encoding.UTF8; public override void Write(char @char) { + if (_squareBracketsNestingLevel == 0) { + if (@char == ';' || @char == '}') { + _allowNextTopLevelAdjacentSquareBrackets = true; + return; + } + else if (!char.IsWhiteSpace(@char) && @char != '[') { + _allowNextTopLevelAdjacentSquareBrackets = false; + } + } + ValidateBrackets(@char, '(', ')', ref _roundBracketsNestingLevel, _roundBracketsAdjacentPairCounts); - ValidateBrackets(@char, '[', ']', ref _squareBracketsNestingLevel, _squareBracketsAdjacentPairCounts); + ValidateBrackets(@char, '[', ']', ref _squareBracketsNestingLevel, _squareBracketsAdjacentPairCounts, _allowNextTopLevelAdjacentSquareBrackets); } - private void ValidateBrackets(char @char, char openBracket, char closeBracket, ref int nestingLevel, int[] adjacentPairCounts) { + private void ValidateBrackets(char @char, char openBracket, char closeBracket, ref int nestingLevel, int[] adjacentPairCounts, bool allowTopLevelAdjacentPairs = false) { if (@char == openBracket) { nestingLevel += 1; if (nestingLevel > BracketsNestingLimit) @@ -48,6 +60,8 @@ private void ValidateBrackets(char @char, char openBracket, char closeBracket, r if (nestingLevel > 0 && @char == closeBracket) { nestingLevel -= 1; + if (nestingLevel == 0 && allowTopLevelAdjacentPairs) + return; adjacentPairCounts[nestingLevel] += 1; if (adjacentPairCounts[nestingLevel] > BracketsAdjacentPairLimit) throw new RoslynSourceTextGuardException($"Exceeded limit on consecutive {openBracket}{closeBracket}."); @@ -55,6 +69,9 @@ private void ValidateBrackets(char @char, char openBracket, char closeBracket, r return; } + if (nestingLevel == 0 && allowTopLevelAdjacentPairs) + return; + if (!char.IsWhiteSpace(@char)) { adjacentPairCounts[nestingLevel] = 0; return; diff --git a/source/Server/MirrorSharp/MirrorSharpModule.cs b/source/Server/MirrorSharp/MirrorSharpModule.cs index e04dd86e3..7a3afe0a1 100644 --- a/source/Server/MirrorSharp/MirrorSharpModule.cs +++ b/source/Server/MirrorSharp/MirrorSharpModule.cs @@ -6,41 +6,41 @@ using MirrorSharp.Advanced.EarlyAccess; using SharpLab.Server.MirrorSharp.Guards; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly] - public class MirrorSharpModule : Module { - protected override void Load(ContainerBuilder builder) { - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As>() - .SingleInstance(); - - builder.RegisterType() - .As>() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - - builder.RegisterType() - .As() - .SingleInstance(); - } +namespace SharpLab.Server.MirrorSharp; + +[UsedImplicitly] +public class MirrorSharpModule : Module { + protected override void Load(ContainerBuilder builder) { + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As>() + .SingleInstance(); + + builder.RegisterType() + .As>() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); + + builder.RegisterType() + .As() + .SingleInstance(); } } \ No newline at end of file diff --git a/source/Server/MirrorSharp/MonitorExceptionLogger.cs b/source/Server/MirrorSharp/MonitorExceptionLogger.cs index aac307d86..868e6a8f5 100644 --- a/source/Server/MirrorSharp/MonitorExceptionLogger.cs +++ b/source/Server/MirrorSharp/MonitorExceptionLogger.cs @@ -1,22 +1,21 @@ using System; -using System.Net.WebSockets; using MirrorSharp.Advanced; +using SharpLab.Server.Common; using SharpLab.Server.Monitoring; -namespace SharpLab.Server.MirrorSharp { - public class MonitorExceptionLogger : IExceptionLogger { - private readonly IMonitor _monitor; +namespace SharpLab.Server.MirrorSharp; +public class MonitorExceptionLogger : IExceptionLogger { + private readonly IExceptionLogFilter _filter; + private readonly IMonitor _monitor; - public MonitorExceptionLogger(IMonitor monitor) { - _monitor = monitor; - } + public MonitorExceptionLogger(IExceptionLogFilter filter, IMonitor monitor) { + _filter = filter; + _monitor = monitor; + } - public void LogException(Exception exception, IWorkSession session) { - // Note/TODO: need to see if OperationCanceledException can be avoided - // https://github.com/ashmind/SharpLab/issues/617 - if (exception is WebSocketException or OperationCanceledException) - return; - _monitor.Exception(exception, session); - } + public void LogException(Exception exception, IWorkSession session) { + if (!_filter.ShouldLog(exception, session)) + return; + _monitor.Exception(exception, session); } } diff --git a/source/Server/MirrorSharp/SetOptionsFromClient.cs b/source/Server/MirrorSharp/SetOptionsFromClient.cs index a3971b013..8db350aaa 100644 --- a/source/Server/MirrorSharp/SetOptionsFromClient.cs +++ b/source/Server/MirrorSharp/SetOptionsFromClient.cs @@ -6,43 +6,43 @@ using SharpLab.Server.Caching; using SharpLab.Server.Common; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class SetOptionsFromClient : ISetOptionsFromClientExtension { - private const string Optimize = "x-optimize"; - private const string Target = "x-target"; - private const string NoCache = "x-no-cache"; +namespace SharpLab.Server.MirrorSharp; - private readonly IDictionary _languages; +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class SetOptionsFromClient : ISetOptionsFromClientExtension { + private const string Optimize = "x-optimize"; + private const string Target = "x-target"; + private const string NoCache = "x-no-cache"; - public SetOptionsFromClient(IReadOnlyList languages) { - _languages = languages.ToDictionary(l => l.LanguageName); - } + private readonly IDictionary _languages; + + public SetOptionsFromClient(IReadOnlyList languages) { + _languages = languages.ToDictionary(l => l.LanguageName); + } - public bool TrySetOption(IWorkSession session, string name, string value) { - switch (name) { - case Optimize: - session.SetOptimize(value); - _languages[session.LanguageName].SetOptimize(session, value); - return true; - case Target: - session.SetTargetName(value); - _languages[session.LanguageName].SetOptionsForTarget(session, value); - return true; - case NoCache: - if (value != "true") - throw new NotSupportedException("Option 'no-cache' can only be set to true."); - // Mostly used to avoid caching on the first change after a cached result was loaded - session.SetCachingDisabled(true); - return true; - default: - #if !DEBUG - // Need to allow unknown options for future compatibility - return true; - #else - return false; - #endif - } + public bool TrySetOption(IWorkSession session, string name, string value) { + switch (name) { + case Optimize: + session.SetOptimize(value); + _languages[session.LanguageName].SetOptimize(session, value); + return true; + case Target: + session.SetTargetName(value); + _languages[session.LanguageName].SetOptionsForTarget(session, value); + return true; + case NoCache: + if (value != "true") + throw new NotSupportedException("Option 'no-cache' can only be set to true."); + // Mostly used to avoid caching on the first change after a cached result was loaded + session.SetCachingDisabled(true); + return true; + default: + #if !DEBUG + // Need to allow unknown options for future compatibility + return true; + #else + return false; + #endif } } } \ No newline at end of file diff --git a/source/Server/MirrorSharp/SlowUpdate.cs b/source/Server/MirrorSharp/SlowUpdate.cs index 6527a7cb2..486646c17 100644 --- a/source/Server/MirrorSharp/SlowUpdate.cs +++ b/source/Server/MirrorSharp/SlowUpdate.cs @@ -16,174 +16,188 @@ using SharpLab.Server.Decompilation; using SharpLab.Server.Decompilation.AstOnly; using SharpLab.Server.Execution; -using SharpLab.Server.Execution.Container; using SharpLab.Server.Explanation; using SharpLab.Server.Monitoring; using LanguageNames = SharpLab.Server.Common.LanguageNames; -namespace SharpLab.Server.MirrorSharp { - [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] - public class SlowUpdate : ISlowUpdateExtension { - private readonly ICSharpTopLevelProgramSupport _topLevelProgramSupport; - private readonly ICompiler _compiler; - private readonly IReadOnlyDictionary _decompilers; - private readonly IReadOnlyDictionary _astTargets; - private readonly IContainerExecutor _containerExecutor; - private readonly IExplainer _explainer; - private readonly RecyclableMemoryStreamManager _memoryStreamManager; - private readonly IMonitor _monitor; - - public SlowUpdate( - ICSharpTopLevelProgramSupport topLevelProgramSupport, - ICompiler compiler, - IReadOnlyCollection decompilers, - IReadOnlyCollection astTargets, - IContainerExecutor containerExecutor, - IExplainer explainer, - RecyclableMemoryStreamManager memoryStreamManager, - IMonitor monitor - ) { - _topLevelProgramSupport = topLevelProgramSupport; - _compiler = compiler; - _decompilers = decompilers.ToDictionary(d => d.LanguageName); - _astTargets = astTargets - .SelectMany(t => t.SupportedLanguageNames.Select(n => (target: t, languageName: n))) - .ToDictionary(x => x.languageName, x => x.target); - _containerExecutor = containerExecutor; - _memoryStreamManager = memoryStreamManager; - _monitor = monitor; - _explainer = explainer; - } +namespace SharpLab.Server.MirrorSharp; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public class SlowUpdate : ISlowUpdateExtension { + private readonly ICSharpTopLevelProgramSupport _topLevelProgramSupport; + private readonly ICompiler _compiler; + private readonly IReadOnlyDictionary _decompilers; + private readonly IReadOnlyDictionary _astTargets; + private readonly IContainerExecutor _containerExecutor; + private readonly IExplainer _explainer; + private readonly RecyclableMemoryStreamManager _memoryStreamManager; + private readonly IFeatureTracker _featureTracker; + private readonly IMonitor _monitor; + private readonly IZeroDimensionMetricMonitor _containerRunCountMonitor; + private readonly IZeroDimensionMetricMonitor _containerFailureCountMonitor; + + public SlowUpdate( + ICSharpTopLevelProgramSupport topLevelProgramSupport, + ICompiler compiler, + IReadOnlyCollection decompilers, + IReadOnlyCollection astTargets, + IContainerExecutor containerExecutor, + IExplainer explainer, + RecyclableMemoryStreamManager memoryStreamManager, + IFeatureTracker featureTracker, + IMonitor monitor + ) { + _topLevelProgramSupport = topLevelProgramSupport; + _compiler = compiler; + _decompilers = decompilers.ToDictionary(d => d.LanguageName); + _astTargets = astTargets + .SelectMany(t => t.SupportedLanguageNames.Select(n => (target: t, languageName: n))) + .ToDictionary(x => x.languageName, x => x.target); + _containerExecutor = containerExecutor; + _memoryStreamManager = memoryStreamManager; + _explainer = explainer; + _featureTracker = featureTracker; + _monitor = monitor; + _containerRunCountMonitor = _monitor.MetricSlow("container-experiment", "Runs: Container"); + _containerFailureCountMonitor = _monitor.MetricSlow("container-experiment", "Runs: Failed"); + } - public async Task ProcessAsync(IWorkSession session, IList diagnostics, CancellationToken cancellationToken) { - //AssemblyLog.Enable(n => $"assembly/{n}.dll"); - PerformanceLog.Checkpoint("SlowUpdate.ProcessAsync.Start"); - var targetName = GetAndEnsureTargetName(session); + public async Task ProcessAsync(IWorkSession session, IList diagnostics, CancellationToken cancellationToken) { + //AssemblyLog.Enable(n => $"assembly/{n}.dll"); + PerformanceLog.Checkpoint("SlowUpdate.ProcessAsync.Start"); + _featureTracker.TrackBranch(); - _topLevelProgramSupport.UpdateOutputKind(session, diagnostics); + var targetName = GetAndEnsureTargetName(session); + _featureTracker.TrackLanguage(session.LanguageName); + _featureTracker.TrackTarget(targetName); - if (targetName is TargetNames.Ast or TargetNames.Explain) { - if (session.LanguageName == LanguageNames.IL) - throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported for IL."); + _topLevelProgramSupport.UpdateOutputKind(session, diagnostics); - var astTarget = _astTargets[session.LanguageName]; - var ast = await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false); - if (targetName == TargetNames.Explain) - return await _explainer.ExplainAsync(ast, session, cancellationToken).ConfigureAwait(false); - return ast; - } + if (targetName is TargetNames.Ast or TargetNames.Explain) { + if (session.LanguageName == LanguageNames.IL) + throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported for IL."); - if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) - return null; + var astTarget = _astTargets[session.LanguageName]; + var ast = await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false); + if (targetName == TargetNames.Explain) + return await _explainer.ExplainAsync(ast, session, cancellationToken).ConfigureAwait(false); + return ast; + } - if (targetName == LanguageNames.VisualBasic) - return VisualBasicNotAvailable; - - if (targetName is not (TargetNames.Run or TargetNames.Verify) && !_decompilers.ContainsKey(targetName)) - throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch."); - - MemoryStream? assemblyStream = null; - MemoryStream? symbolStream = null; - try { - assemblyStream = _memoryStreamManager.GetStream(); - if (targetName is TargetNames.Run or TargetNames.IL) - symbolStream = _memoryStreamManager.GetStream(); - - var compilationStopwatch = session.ShouldReportPerformance() ? Stopwatch.StartNew() : null; - var compiled = await _compiler.TryCompileToStreamAsync(assemblyStream, symbolStream, session, diagnostics, cancellationToken).ConfigureAwait(false); - compilationStopwatch?.Stop(); - if (!compiled.assembly) { - assemblyStream.Dispose(); - symbolStream?.Dispose(); - return null; - } + if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error)) + return null; - if (targetName == TargetNames.Verify) { - assemblyStream.Dispose(); - symbolStream?.Dispose(); - return "✔️ Compilation completed."; - } + if (targetName == LanguageNames.VisualBasic) + return VisualBasicNotAvailable; - assemblyStream.Seek(0, SeekOrigin.Begin); - symbolStream?.Seek(0, SeekOrigin.Begin); - AssemblyLog.Log("1.Compiled", assemblyStream, compiled.symbols ? symbolStream : null); - - var streams = new CompilationStreamPair(assemblyStream, compiled.symbols ? symbolStream : null); - if (targetName == TargetNames.Run) { - try { - var result = await _containerExecutor.ExecuteAsync(streams, session, cancellationToken); - if (compilationStopwatch != null) { - // TODO: Prettify - // output += $"\n COMPILATION: {compilationStopwatch.ElapsedMilliseconds,15}ms"; - } - streams.Dispose(); - _monitor.Metric(ContainerExperimentMetrics.ContainerRunCount, 1); - return result; - } - catch { - _monitor.Metric(ContainerExperimentMetrics.ContainerFailureCount, 1); - throw; - } - } + if (targetName is not (TargetNames.Run or TargetNames.Verify) && !_decompilers.ContainsKey(targetName)) + throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch."); - // it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult() - return streams; + _featureTracker.TrackOptimize(session.GetOptimize()!); + + MemoryStream? assemblyStream = null; + MemoryStream? symbolStream = null; + try { + assemblyStream = _memoryStreamManager.GetStream(); + if (targetName is TargetNames.Run or TargetNames.IL or TargetNames.RunIL) + symbolStream = _memoryStreamManager.GetStream(); + + var compilationStopwatch = session.ShouldReportPerformance() ? Stopwatch.StartNew() : null; + var compiled = await _compiler.TryCompileToStreamAsync(assemblyStream, symbolStream, session, diagnostics, cancellationToken).ConfigureAwait(false); + compilationStopwatch?.Stop(); + if (!compiled.assembly) { + assemblyStream.Dispose(); + symbolStream?.Dispose(); + return null; } - catch { - assemblyStream?.Dispose(); + + if (targetName == TargetNames.Verify) { + assemblyStream.Dispose(); symbolStream?.Dispose(); - throw; + return "✔️ Compilation completed."; } - } - public void WriteResult(IFastJsonWriter writer, object? result, IWorkSession session) { - session.SetLastSlowUpdateResult(result); + assemblyStream.Seek(0, SeekOrigin.Begin); + symbolStream?.Seek(0, SeekOrigin.Begin); + #if DEBUG + DiagnosticLog.LogAssembly("1.Compiled", assemblyStream, compiled.symbols ? symbolStream : null); + #endif - if (result == null) { - writer.WriteValue((string?)null); - return; + var streams = new CompilationStreamPair(assemblyStream, compiled.symbols ? symbolStream : null); + if (targetName == TargetNames.Run) { + try { + var result = await _containerExecutor.ExecuteAsync(streams, session, cancellationToken); + if (compilationStopwatch != null) { + // TODO: Prettify + // output += $"\n COMPILATION: {compilationStopwatch.ElapsedMilliseconds,15}ms"; + } + streams.Dispose(); + _containerRunCountMonitor.Track(1); + return result; + } + catch { + _containerFailureCountMonitor.Track(1); + throw; + } } - if (result is string s) { - writer.WriteValue(s); - return; - } + // it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult() + return streams; + } + catch { + assemblyStream?.Dispose(); + symbolStream?.Dispose(); + throw; + } + } - var targetName = GetAndEnsureTargetName(session); - if (targetName == TargetNames.Ast) { - var astTarget = _astTargets[session.LanguageName]; - astTarget.SerializeAst(result, writer, session); - return; - } + public void WriteResult(IFastJsonWriter writer, object? result, IWorkSession session) { + session.SetLastSlowUpdateResult(result); - if (targetName == TargetNames.Explain) { - _explainer.Serialize((ExplanationResult)result, writer); - return; - } + if (result == null) { + writer.WriteValue((string?)null); + return; + } - if (targetName == TargetNames.Run) { - writer.WriteValue(((ContainerExecutionResult)result).Output); - return; - } + if (result is string s) { + writer.WriteValue(s); + return; + } - var decompiler = _decompilers[targetName]; - using (var streams = (CompilationStreamPair)result) - using (var stringWriter = writer.OpenString()) { - decompiler.Decompile(streams, stringWriter); - } + var targetName = GetAndEnsureTargetName(session); + if (targetName == TargetNames.Ast) { + var astTarget = _astTargets[session.LanguageName]; + astTarget.SerializeAst(result, writer, session); + return; + } + + if (targetName == TargetNames.Explain) { + _explainer.Serialize((ExplanationResult)result, writer); + return; } - private const string VisualBasicNotAvailable = - "' Unfortunately, Visual Basic decompilation is no longer supported.\r\n" + - "' \r\n" + - "' All decompilation in SharpLab is provided by ILSpy, and latest ILSpy does not suport VB.\r\n" + - "' If you are interested in VB, please discuss or contribute at https://github.com/icsharpcode/ILSpy."; - - private string GetAndEnsureTargetName(IWorkSession session) { - var targetName = session.GetTargetName(); - if (targetName == null) - throw new InvalidOperationException("Target is not set on the session (timing issue?). Please try reloading."); - return targetName; + if (targetName == TargetNames.Run) { + writer.WriteValue(((ContainerExecutionResult)result).Output); + return; } + + var decompiler = _decompilers[targetName]; + using (var streams = (CompilationStreamPair)result) + using (var stringWriter = writer.OpenString()) { + decompiler.Decompile(streams, stringWriter, session); + } + } + + private const string VisualBasicNotAvailable = + "' Unfortunately, Visual Basic decompilation is no longer supported.\r\n" + + "' \r\n" + + "' All decompilation in SharpLab is provided by ILSpy, and latest ILSpy does not suport VB.\r\n" + + "' If you are interested in VB, please discuss or contribute at https://github.com/icsharpcode/ILSpy."; + + private string GetAndEnsureTargetName(IWorkSession session) { + var targetName = session.GetTargetName(); + if (targetName == null) + throw new InvalidOperationException("Target is not set on the session (timing issue?). Please try reloading."); + return targetName; } } \ No newline at end of file diff --git a/source/Server/MirrorSharp/WorkSessionExtensions.cs b/source/Server/MirrorSharp/WorkSessionExtensions.cs index 2c4bad6f9..3a5ce0474 100644 --- a/source/Server/MirrorSharp/WorkSessionExtensions.cs +++ b/source/Server/MirrorSharp/WorkSessionExtensions.cs @@ -2,47 +2,47 @@ using AshMind.Extensions; using MirrorSharp.Advanced; -namespace SharpLab.Server.MirrorSharp { - public static class WorkSessionExtensions { - public static string? GetTargetName(this IWorkSession session) { - return (string?)session.ExtensionData.GetValueOrDefault("TargetName"); - } +namespace SharpLab.Server.MirrorSharp; - public static void SetTargetName(this IWorkSession session, string value) { - session.ExtensionData["TargetName"] = value; - } +public static class WorkSessionExtensions { + public static string? GetTargetName(this IWorkSession session) { + return (string?)session.ExtensionData.GetValueOrDefault("TargetName"); + } - public static string? GetOptimize(this IWorkSession session) { - return (string?)session.ExtensionData.GetValueOrDefault("Optimize"); - } + public static void SetTargetName(this IWorkSession session, string value) { + session.ExtensionData["TargetName"] = value; + } - public static void SetOptimize(this IWorkSession session, string value) { - session.ExtensionData["Optimize"] = value; - } + public static string? GetOptimize(this IWorkSession session) { + return (string?)session.ExtensionData.GetValueOrDefault("Optimize"); + } - public static bool ShouldReportPerformance(this IWorkSession session) { - return (bool?)session.ExtensionData.GetValueOrDefault("DebugIncludePerformance") ?? false; - } + public static void SetOptimize(this IWorkSession session, string value) { + session.ExtensionData["Optimize"] = value; + } - public static void SetShouldReportPerformance(this IWorkSession session, bool value) { - session.ExtensionData["DebugIncludePerformance"] = value; - } + public static bool ShouldReportPerformance(this IWorkSession session) { + return (bool?)session.ExtensionData.GetValueOrDefault("DebugIncludePerformance") ?? false; + } - public static object? GetLastSlowUpdateResult(this IWorkSession session) { - return session.ExtensionData.GetValueOrDefault("LastSlowUpdateResult"); - } + public static void SetShouldReportPerformance(this IWorkSession session, bool value) { + session.ExtensionData["DebugIncludePerformance"] = value; + } - public static void SetLastSlowUpdateResult(this IWorkSession session, object? value) { - session.ExtensionData["LastSlowUpdateResult"] = value; - } + public static object? GetLastSlowUpdateResult(this IWorkSession session) { + return session.ExtensionData.GetValueOrDefault("LastSlowUpdateResult"); + } + + public static void SetLastSlowUpdateResult(this IWorkSession session, object? value) { + session.ExtensionData["LastSlowUpdateResult"] = value; + } - public static string GetSessionId(this IWorkSession session) { - var id = (string?)session.ExtensionData.GetValueOrDefault("SessionId"); - if (id == null) { - id = Guid.NewGuid().ToString(); - session.ExtensionData["SessionId"] = id; - } - return id; + public static string GetSessionId(this IWorkSession session) { + var id = (string?)session.ExtensionData.GetValueOrDefault("SessionId"); + if (id == null) { + id = Guid.NewGuid().ToString(); + session.ExtensionData["SessionId"] = id; } + return id; } } \ No newline at end of file diff --git a/source/Server/Monitoring/DefaultLoggerMetricMonitor.cs b/source/Server/Monitoring/DefaultLoggerMetricMonitor.cs new file mode 100644 index 000000000..9fea7da20 --- /dev/null +++ b/source/Server/Monitoring/DefaultLoggerMetricMonitor.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Logging; + +namespace SharpLab.Server.Monitoring; + +public class DefaultLoggerMetricMonitor : IZeroDimensionMetricMonitor, IOneDimensionMetricMonitor { + private readonly ILogger _logger; + private readonly string _namespace; + private readonly string _name; + + public DefaultLoggerMetricMonitor( + ILogger logger, + string @namespace, string name + ) { + Argument.NotNull(nameof(logger), logger); + Argument.NotNullOrEmpty(nameof(@namespace), @namespace); + Argument.NotNullOrEmpty(nameof(name), name); + + _logger = logger; + _namespace = @namespace; + _name = name; + } + + public void Track(double value) { + _logger.LogInformation("Metric {Namespace} {Name}: {Value}.", _namespace, _name, value); + } + + public void Track(string dimension, double value) { + _logger.LogInformation("Metric {Namespace} {Name}: {Dimension} {Value}.", _namespace, _name, dimension, value); + } +} diff --git a/source/Server/Monitoring/DefaultLoggerMonitor.cs b/source/Server/Monitoring/DefaultLoggerMonitor.cs index aee0478a1..b07299ca2 100644 --- a/source/Server/Monitoring/DefaultLoggerMonitor.cs +++ b/source/Server/Monitoring/DefaultLoggerMonitor.cs @@ -4,20 +4,28 @@ using MirrorSharp.Advanced; using SharpLab.Server.MirrorSharp; -namespace SharpLab.Server.Monitoring { - public class DefaultLoggerMonitor : IMonitor { - private readonly ILogger _logger; +namespace SharpLab.Server.Monitoring; +public class DefaultLoggerMonitor : IMonitor { + private readonly Func<(string @namespace, string name), DefaultLoggerMetricMonitor> _createMetricMonitor; + private readonly ILogger _logger; - public DefaultLoggerMonitor(ILogger logger) { - _logger = logger; - } + public DefaultLoggerMonitor( + Func<(string @namespace, string name), DefaultLoggerMetricMonitor> createMetricMonitor, + ILogger logger + ) { + _createMetricMonitor = createMetricMonitor; + _logger = logger; + } + + public IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name) { + return _createMetricMonitor((@namespace, name)); + } - public void Metric(MonitorMetric metric, double value) { - _logger.LogInformation("Metric {Namespace} {Name}: {Value}.", metric.Namespace, metric.Name, value); - } + public IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension) { + return _createMetricMonitor((@namespace, name)); + } - public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { - _logger.LogError(exception, "[{SessionId}] Exception: {Message}", session?.GetSessionId(), exception.Message); - } + public void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null) { + _logger.LogError(exception, "[{SessionId}] Exception: {Message}", session?.GetSessionId(), exception.Message); } } diff --git a/source/Server/Monitoring/IMonitor.cs b/source/Server/Monitoring/IMonitor.cs index 076562fcc..4445769f9 100644 --- a/source/Server/Monitoring/IMonitor.cs +++ b/source/Server/Monitoring/IMonitor.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using MirrorSharp.Advanced; -namespace SharpLab.Server.Monitoring { - public interface IMonitor { - void Metric(MonitorMetric metric, double value); - void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null); - } +namespace SharpLab.Server.Monitoring; +public interface IMonitor { + IZeroDimensionMetricMonitor MetricSlow(string @namespace, string name); + IOneDimensionMetricMonitor MetricSlow(string @namespace, string name, string dimension); + void Exception(Exception exception, IWorkSession? session, IDictionary? extras = null); } diff --git a/source/Server/Monitoring/IOneDimensionMetricMonitor.cs b/source/Server/Monitoring/IOneDimensionMetricMonitor.cs new file mode 100644 index 000000000..1d72a3333 --- /dev/null +++ b/source/Server/Monitoring/IOneDimensionMetricMonitor.cs @@ -0,0 +1,5 @@ +namespace SharpLab.Server.Monitoring; + +public interface IOneDimensionMetricMonitor { + void Track(string dimension, double value); +} diff --git a/source/Server/Monitoring/IZeroDimensionMetricMonitor.cs b/source/Server/Monitoring/IZeroDimensionMetricMonitor.cs new file mode 100644 index 000000000..2aac8df2f --- /dev/null +++ b/source/Server/Monitoring/IZeroDimensionMetricMonitor.cs @@ -0,0 +1,5 @@ +namespace SharpLab.Server.Monitoring; + +public interface IZeroDimensionMetricMonitor { + void Track(double value); +} diff --git a/source/Server/Monitoring/MonitorMetric.cs b/source/Server/Monitoring/MonitorMetric.cs deleted file mode 100644 index 1eac1b6ec..000000000 --- a/source/Server/Monitoring/MonitorMetric.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace SharpLab.Server.Monitoring { - public class MonitorMetric { - public MonitorMetric(string @namespace, string name) { - Argument.NotNullOrEmpty(nameof(@namespace), @namespace); - Argument.NotNullOrEmpty(nameof(name), name); - - Namespace = @namespace; - Name = name; - } - - public string Namespace { get; } - public string Name { get; } - } -} diff --git a/source/Server/Monitoring/MonitoringModule.cs b/source/Server/Monitoring/MonitoringModule.cs index 62360d86a..05f27aed4 100644 --- a/source/Server/Monitoring/MonitoringModule.cs +++ b/source/Server/Monitoring/MonitoringModule.cs @@ -1,14 +1,28 @@ using Autofac; using JetBrains.Annotations; +using System; -namespace SharpLab.Server.Monitoring { - [UsedImplicitly] - public class MonitoringModule : Module { - protected override void Load(ContainerBuilder builder) { - builder.RegisterType() - .As() - .SingleInstance() - .PreserveExistingDefaults(); - } +namespace SharpLab.Server.Monitoring; +[UsedImplicitly] +public class MonitoringModule : Module { + protected override void Load(ContainerBuilder builder) { + builder.RegisterType() + .AsSelf() + .InstancePerDependency(); + + builder.RegisterType() + .As() + .WithParameter( + (p, _) => p.ParameterType == typeof(Func<(string, string), DefaultLoggerMetricMonitor>), + (_, c) => { + var context = c.Resolve(); + return ((string @namespace, string name) args) => context.Resolve( + new NamedParameter("namespace", args.@namespace), + new NamedParameter("name", args.name) + ); + } + ) + .SingleInstance() + .PreserveExistingDefaults(); } } \ No newline at end of file diff --git a/source/Server/Server.csproj b/source/Server/Server.csproj index 80d0b7c9a..0286d4676 100644 --- a/source/Server/Server.csproj +++ b/source/Server/Server.csproj @@ -1,6 +1,6 @@ - net6.0 + net9.0 InProcess SharpLab.Server SharpLab.Server @@ -31,36 +31,44 @@ - + - + - - - - - + + + + + + + + - - - + + + + + - - - - - + + + + + diff --git a/source/Server/Startup.cs b/source/Server/Startup.cs index c980615ae..949a1e846 100644 --- a/source/Server/Startup.cs +++ b/source/Server/Startup.cs @@ -15,105 +15,113 @@ using SharpLab.Server.Common; using SharpLab.Server.Common.Diagnostics; using Microsoft.AspNetCore.Http; +using System.Threading.Tasks; -namespace SharpLab.Server { - public class Startup { - // Chrome would limit to 10 mins I believe - private static readonly TimeSpan CorsPreflightMaxAge = TimeSpan.FromHours(1); +namespace SharpLab.Server; - public void ConfigureServices(IServiceCollection services) { - services.AddHttpClient(); - services.AddCors(); - services.AddControllers(); - } +public class Startup { + // Chrome would limit to 10 mins I believe + private static readonly TimeSpan CorsPreflightMaxAge = TimeSpan.FromHours(1); - public void ConfigureContainer(ContainerBuilder builder) { - var assembly = Assembly.GetExecutingAssembly(); + public void ConfigureServices(IServiceCollection services) { + services.AddHttpClient(); + services.AddCors(); + services.AddControllers(); + } - builder - .RegisterAssemblyModulesInDirectoryOf(assembly) - .WhereFileMatches("SharpLab.*"); - } + public void ConfigureContainer(ContainerBuilder builder) { + var assembly = Assembly.GetExecutingAssembly(); - public static MirrorSharpOptions CreateMirrorSharpOptions(ILifetimeScope container) { - var options = new MirrorSharpOptions { - IncludeExceptionDetails = true, - StatusTestCommands = { - ('O', "x-optimize=debug,x-target=C#,x-no-cache=true,language=C#"), - ('R', "0:0:0::using System; public class C { public void M() { } }"), - ('U', "") - } - }; - var languages = container.Resolve(); - foreach (var language in languages) { - language.SlowSetup(options); + builder + .RegisterAssemblyModulesInDirectoryOf(assembly) + .WhereFileMatches("SharpLab.*"); + } + + public static MirrorSharpOptions CreateMirrorSharpOptions(ILifetimeScope container) { + var options = new MirrorSharpOptions { + IncludeExceptionDetails = true, + StatusTestCommands = { + ('O', "x-optimize=debug,x-target=C#,x-no-cache=true,language=C#"), + ('R', "0:0:0::using System; public class C { public void M() { } }"), + ('U', "") } - PerformanceLog.Checkpoint("Startup.CreateMirrorSharpOptions.End"); - return options; + }; + var languages = container.Resolve(); + foreach (var language in languages) { + language.SlowSetup(options); } + PerformanceLog.Checkpoint("Startup.CreateMirrorSharpOptions.End"); + return options; + } - public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + + app.UseRouting(); + app.UseCors(p => p + .AllowAnyHeader() + .AllowAnyOrigin() + .AllowAnyMethod() + .SetPreflightMaxAge(CorsPreflightMaxAge) + ); + + app.UseWebSockets(); + app.MapMirrorSharp("/mirrorsharp", CreateMirrorSharpOptions(app.ApplicationServices.GetAutofacRoot())); + + app.UseEndpoints(e => { + MapStatus(e); + MapBranchVersion(e, env); if (env.IsDevelopment()) - app.UseDeveloperExceptionPage(); - - app.UseRouting(); - app.UseCors(p => p - .AllowAnyHeader() - .AllowAnyOrigin() - .AllowAnyMethod() - .SetPreflightMaxAge(CorsPreflightMaxAge) - ); - - app.UseWebSockets(); - app.MapMirrorSharp("/mirrorsharp", CreateMirrorSharpOptions(app.ApplicationServices.GetAutofacRoot())); - - app.UseEndpoints(e => { - MapStatus(e); - MapBranchVersion(e, env); - if (env.IsDevelopment()) - MapFeatureFlags(e); - MapOtherEndpoints(e); - - e.MapControllers(); - }); - } + MapFeatureFlags(e); + MapOtherEndpoints(e); - private void MapStatus(IEndpointRouteBuilder e) { - var okBytes = new ReadOnlyMemory(Encoding.UTF8.GetBytes("OK")); - e.MapGet("/status", context => { - context.Response.ContentType = MediaTypeNames.Text.Plain; - return context.Response.BodyWriter.WriteAsync(okBytes, context.RequestAborted).AsTask(); - }); - } + e.MapControllers(); + }); + } - private void MapFeatureFlags(IEndpointRouteBuilder e) { - e.MapGet("/featureflags/{key:alpha}", static context => { - var key = (string)context.GetRouteValue("key")!; - var featureFlagClient = context.RequestServices.GetRequiredService(); + private void MapStatus(IEndpointRouteBuilder e) { + var okBytes = new ReadOnlyMemory(Encoding.UTF8.GetBytes("OK")); + e.MapGet("/status", context => { + context.Response.ContentType = MediaTypeNames.Text.Plain; + return WriteResponseBodyAsync(context, okBytes); + }); + } - return context.Response.WriteAsync( - featureFlagClient.GetInt32Flag(key)?.ToString() ?? "", - context.RequestAborted - ); - }); - } + private void MapFeatureFlags(IEndpointRouteBuilder e) { + e.MapGet("/featureflags/{key:alpha}", static context => { + var key = (string)context.GetRouteValue("key")!; + var featureFlagClient = context.RequestServices.GetRequiredService(); - // Temporary: until build is updated to something better than a json file on site itself - protected virtual void MapBranchVersion(IEndpointRouteBuilder endpoints, IWebHostEnvironment env) { - var file = env.WebRootFileProvider.GetFileInfo("branch-version.json"); - if (!file.Exists) - return; - - using var stream = file.CreateReadStream(); - var bytes = new byte[stream.Length]; - stream.Read(bytes, 0, bytes.Length); - endpoints.MapGet("/branch-version.json", context => { - context.Response.ContentType = MediaTypeNames.Application.Json; - return context.Response.BodyWriter.WriteAsync(bytes, context.RequestAborted).AsTask(); - }); - } + return context.Response.WriteAsync( + featureFlagClient.GetInt32Flag(key)?.ToString() ?? "", + context.RequestAborted + ); + }); + } - protected virtual void MapOtherEndpoints(IEndpointRouteBuilder endpoints) { - } + // Temporary: until build is updated to something better than a json file on site itself + protected virtual void MapBranchVersion(IEndpointRouteBuilder endpoints, IWebHostEnvironment env) { + var file = env.WebRootFileProvider.GetFileInfo("branch-version.json"); + if (!file.Exists) + return; + + using var stream = file.CreateReadStream(); + var bytes = new byte[stream.Length]; + stream.ReadExactly(bytes, 0, bytes.Length); + endpoints.MapGet("/branch-version.json", context => { + context.Response.ContentType = MediaTypeNames.Application.Json; + return WriteResponseBodyAsync(context, bytes); + }); + } + + private Task WriteResponseBodyAsync(HttpContext context, ReadOnlyMemory body) { + var writeTask = context.Response.BodyWriter.WriteAsync(body, context.RequestAborted); + return writeTask.IsCompletedSuccessfully + ? Task.CompletedTask + : writeTask.AsTask(); + } + + protected virtual void MapOtherEndpoints(IEndpointRouteBuilder endpoints) { } } diff --git a/source/SharpLab.sln b/source/SharpLab.sln index b269d47be..54df06cac 100644 --- a/source/SharpLab.sln +++ b/source/SharpLab.sln @@ -46,19 +46,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Container.Warmup", "Contain EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mirrorsharp", "mirrorsharp", "{857B6AAC-168B-4C0A-AC0E-9471B1133E18}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "#external\mirrorsharp\Common\Common.csproj", "{85D37C09-55DB-4826-A82C-00306E7F7FFD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common", "#external\mirrorsharp-codemirror-6-preview\Common\Common.csproj", "{85D37C09-55DB-4826-A82C-00306E7F7FFD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp", "#external\mirrorsharp\FSharp\FSharp.csproj", "{4CB3E2A1-CBB9-40B5-A8E5-5E5BE0A43440}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSharp", "#external\mirrorsharp-codemirror-6-preview\FSharp\FSharp.csproj", "{4CB3E2A1-CBB9-40B5-A8E5-5E5BE0A43440}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore", "#external\mirrorsharp\AspNetCore\AspNetCore.csproj", "{956D5368-42DC-4449-BE26-3114A0FFA26A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore", "#external\mirrorsharp-codemirror-6-preview\AspNetCore\AspNetCore.csproj", "{956D5368-42DC-4449-BE26-3114A0FFA26A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualBasic", "#external\mirrorsharp\VisualBasic\VisualBasic.csproj", "{92675C61-F0E7-4317-AD8F-BF40246CA3BE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VisualBasic", "#external\mirrorsharp-codemirror-6-preview\VisualBasic\VisualBasic.csproj", "{92675C61-F0E7-4317-AD8F-BF40246CA3BE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IL", "#external\mirrorsharp\IL\IL.csproj", "{F349EC21-2D0A-4BCF-8416-33783AC420CF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IL", "#external\mirrorsharp-codemirror-6-preview\IL\IL.csproj", "{F349EC21-2D0A-4BCF-8416-33783AC420CF}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testing", "#external\mirrorsharp\Testing\Testing.csproj", "{25D47016-569C-4CB6-9CB3-B2B8243B3485}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testing", "#external\mirrorsharp-codemirror-6-preview\Testing\Testing.csproj", "{25D47016-569C-4CB6-9CB3-B2B8243B3485}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin", "#external\mirrorsharp\Owin\Owin.csproj", "{364367F9-D5DF-4DE0-9BF5-230144E00CE9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Owin", "#external\mirrorsharp-codemirror-6-preview\Owin\Owin.csproj", "{364367F9-D5DF-4DE0-9BF5-230144E00CE9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mobius.ILasm", "Mobius.ILasm", "{F2DC8AAC-B7A3-44CA-97C8-6DA6F6285EFA}" EndProject @@ -68,9 +68,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobius.ILasm.Cli", "#extern EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobius.ILasm.Tests", "#external\Mobius.ILasm\Mobius.ILasm.Tests\Mobius.ILasm.Tests.csproj", "{7813B6ED-1EFF-4207-BB6C-F9F2C0F59308}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "#external\mirrorsharp\Tests\Tests.csproj", "{C997F73F-0CAC-4558-B2D6-252131C0DBE0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "#external\mirrorsharp-codemirror-6-preview\Tests\Tests.csproj", "{C997F73F-0CAC-4558-B2D6-252131C0DBE0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Php", "#external\mirrorsharp\Php\Php.csproj", "{8C981375-A016-4B40-B54C-7A324A4D51F0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Php", "#external\mirrorsharp-codemirror-6-preview\Php\Php.csproj", "{8C981375-A016-4B40-B54C-7A324A4D51F0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mobius.ILasm.Tests.SourceGenerator", "#external\Mobius.ILasm\Mobius.ILasm.Tests.SourceGenerator\Mobius.ILasm.Tests.SourceGenerator.csproj", "{09A00830-68F3-4F04-9322-8F83E898A554}" EndProject @@ -78,19 +78,39 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fragile", "Fragile", "{5792 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fragile", "#external\Fragile\Fragile\Fragile.csproj", "{FD74AE76-B79C-4540-96B6-223A5E12B89A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn33", "#external\mirrorsharp\Internal.Roslyn33\Internal.Roslyn33.csproj", "{4DD9FAA9-682E-46A6-8AD3-EABFF677C14A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn33", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn33\Internal.Roslyn33.csproj", "{4DD9FAA9-682E-46A6-8AD3-EABFF677C14A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn36", "#external\mirrorsharp\Internal.Roslyn36\Internal.Roslyn36.csproj", "{1FDC16C3-9941-4567-B969-32A7ECA7A237}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn36", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn36\Internal.Roslyn36.csproj", "{1FDC16C3-9941-4567-B969-32A7ECA7A237}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn41", "#external\mirrorsharp\Internal.Roslyn41\Internal.Roslyn41.csproj", "{FA2F0723-B881-4DD6-AD6E-09AF2154D917}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn41", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn41\Internal.Roslyn41.csproj", "{FA2F0723-B881-4DD6-AD6E-09AF2154D917}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn42", "#external\mirrorsharp\Internal.Roslyn42\Internal.Roslyn42.csproj", "{2AF6A3B6-85AD-497D-A8B3-56586796B976}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn42", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn42\Internal.Roslyn42.csproj", "{2AF6A3B6-85AD-497D-A8B3-56586796B976}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.RoslynLatest", "#external\mirrorsharp\Tests.RoslynLatest\Tests.RoslynLatest.csproj", "{790D1C86-D15B-4CE9-9FEE-F72E32AE2C4C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.RoslynLatest", "#external\mirrorsharp-codemirror-6-preview\Tests.RoslynLatest\Tests.RoslynLatest.csproj", "{790D1C86-D15B-4CE9-9FEE-F72E32AE2C4C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.RoslynInternals", "#external\mirrorsharp\Internal.RoslynInternals\Internal.RoslynInternals.csproj", "{35658C61-7D7E-4507-8355-0496FA7DA4E7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.RoslynInternals", "#external\mirrorsharp-codemirror-6-preview\Internal.RoslynInternals\Internal.RoslynInternals.csproj", "{35658C61-7D7E-4507-8355-0496FA7DA4E7}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn43", "#external\mirrorsharp\Internal.Roslyn43\Internal.Roslyn43.csproj", "{E378A792-A0DE-4BD4-8473-B50EC92209FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn43", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn43\Internal.Roslyn43.csproj", "{E378A792-A0DE-4BD4-8473-B50EC92209FD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn44", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn44\Internal.Roslyn44.csproj", "{23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests.Roslyn44", "#external\mirrorsharp-codemirror-6-preview\Tests.Roslyn44\Tests.Roslyn44.csproj", "{F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn45", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn45\Internal.Roslyn45.csproj", "{B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn46", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn46\Internal.Roslyn46.csproj", "{2042090B-E2E7-4EC9-8A97-48C4F2013861}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn47", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn47\Internal.Roslyn47.csproj", "{0884F923-37B8-4728-A3EB-AD28CD38A0B6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn48", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn48\Internal.Roslyn48.csproj", "{9D0D0F2F-37BC-485B-AF47-00788E5092A2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn49", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn49\Internal.Roslyn49.csproj", "{70C3477B-8A46-480A-AB1D-0DCD486A55AD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn410", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn410\Internal.Roslyn410.csproj", "{23253C8E-341C-4613-9834-E7CDBE2D88BA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Internal.Roslyn411", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn411\Internal.Roslyn411.csproj", "{A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internal.Roslyn412", "#external\mirrorsharp-codemirror-6-preview\Internal.Roslyn412\Internal.Roslyn412.csproj", "{4CAF1FEC-CAC2-44BE-A72B-540877583C36}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -141,20 +161,20 @@ Global {AD185E40-0431-4C99-BB89-18D48C9798DC}.Release|x64.Build.0 = Release|Any CPU {AD185E40-0431-4C99-BB89-18D48C9798DC}.Release|x86.ActiveCfg = Release|Any CPU {AD185E40-0431-4C99-BB89-18D48C9798DC}.Release|x86.Build.0 = Release|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|Any CPU.ActiveCfg = Debug|x64 + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|Any CPU.Build.0 = Debug|x64 {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|x64.ActiveCfg = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|x64.Build.0 = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|x86.ActiveCfg = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug|x86.Build.0 = Debug|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|Any CPU.ActiveCfg = Debug|x64 + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|Any CPU.Build.0 = Debug|x64 {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|x64.Build.0 = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Debug-Vsix|x86.Build.0 = Debug|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|Any CPU.Build.0 = Release|Any CPU + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|Any CPU.ActiveCfg = Release|x64 + {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|Any CPU.Build.0 = Release|x64 {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|x64.ActiveCfg = Release|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|x64.Build.0 = Release|Any CPU {D8EF5801-AA5E-43D2-A19D-568D56D23F8D}.Release|x86.ActiveCfg = Release|Any CPU @@ -285,20 +305,20 @@ Global {73E28B1D-A1A8-491D-84AC-B3564FF607E1}.Release|x64.Build.0 = Release|Any CPU {73E28B1D-A1A8-491D-84AC-B3564FF607E1}.Release|x86.ActiveCfg = Release|Any CPU {73E28B1D-A1A8-491D-84AC-B3564FF607E1}.Release|x86.Build.0 = Release|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|Any CPU.ActiveCfg = Debug|x64 + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|Any CPU.Build.0 = Debug|x64 {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|x64.ActiveCfg = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|x64.Build.0 = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|x86.ActiveCfg = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug|x86.Build.0 = Debug|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|Any CPU.ActiveCfg = Debug|x64 + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|Any CPU.Build.0 = Debug|x64 {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|x64.Build.0 = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Debug-Vsix|x86.Build.0 = Debug|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|Any CPU.Build.0 = Release|Any CPU + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|Any CPU.ActiveCfg = Release|x64 + {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|Any CPU.Build.0 = Release|x64 {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|x64.ActiveCfg = Release|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|x64.Build.0 = Release|Any CPU {7724CEA2-C6A7-4C24-B734-1E307DD59093}.Release|x86.ActiveCfg = Release|Any CPU @@ -749,6 +769,186 @@ Global {E378A792-A0DE-4BD4-8473-B50EC92209FD}.Release|x64.Build.0 = Release|Any CPU {E378A792-A0DE-4BD4-8473-B50EC92209FD}.Release|x86.ActiveCfg = Release|Any CPU {E378A792-A0DE-4BD4-8473-B50EC92209FD}.Release|x86.Build.0 = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|x64.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|x64.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|x86.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug|x86.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|Any CPU.Build.0 = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|x64.ActiveCfg = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|x64.Build.0 = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|x86.ActiveCfg = Release|Any CPU + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6}.Release|x86.Build.0 = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|x64.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|x64.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|x86.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug|x86.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|Any CPU.Build.0 = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|x64.ActiveCfg = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|x64.Build.0 = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|x86.ActiveCfg = Release|Any CPU + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8}.Release|x86.Build.0 = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|x64.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|x64.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|x86.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug|x86.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|Any CPU.Build.0 = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|x64.ActiveCfg = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|x64.Build.0 = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|x86.ActiveCfg = Release|Any CPU + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7}.Release|x86.Build.0 = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|x64.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|x64.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|x86.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug|x86.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|Any CPU.Build.0 = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|x64.ActiveCfg = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|x64.Build.0 = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|x86.ActiveCfg = Release|Any CPU + {2042090B-E2E7-4EC9-8A97-48C4F2013861}.Release|x86.Build.0 = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|x64.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|x64.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|x86.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug|x86.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|Any CPU.Build.0 = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|x64.ActiveCfg = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|x64.Build.0 = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|x86.ActiveCfg = Release|Any CPU + {0884F923-37B8-4728-A3EB-AD28CD38A0B6}.Release|x86.Build.0 = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|x64.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|x64.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|x86.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug|x86.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|Any CPU.Build.0 = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|x64.ActiveCfg = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|x64.Build.0 = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|x86.ActiveCfg = Release|Any CPU + {9D0D0F2F-37BC-485B-AF47-00788E5092A2}.Release|x86.Build.0 = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|x64.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|x64.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|x86.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug|x86.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|Any CPU.Build.0 = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|x64.ActiveCfg = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|x64.Build.0 = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|x86.ActiveCfg = Release|Any CPU + {70C3477B-8A46-480A-AB1D-0DCD486A55AD}.Release|x86.Build.0 = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|x64.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|x64.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|x86.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug|x86.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|Any CPU.Build.0 = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|x64.ActiveCfg = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|x64.Build.0 = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|x86.ActiveCfg = Release|Any CPU + {23253C8E-341C-4613-9834-E7CDBE2D88BA}.Release|x86.Build.0 = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|x64.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|x64.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|x86.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug|x86.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|Any CPU.Build.0 = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|x64.ActiveCfg = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|x64.Build.0 = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|x86.ActiveCfg = Release|Any CPU + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267}.Release|x86.Build.0 = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|x64.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|x64.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|x86.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug|x86.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|Any CPU.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|Any CPU.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|x64.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|x64.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|x86.ActiveCfg = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Debug-Vsix|x86.Build.0 = Debug|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|Any CPU.Build.0 = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|x64.ActiveCfg = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|x64.Build.0 = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|x86.ActiveCfg = Release|Any CPU + {4CAF1FEC-CAC2-44BE-A72B-540877583C36}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -786,6 +986,16 @@ Global {790D1C86-D15B-4CE9-9FEE-F72E32AE2C4C} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} {35658C61-7D7E-4507-8355-0496FA7DA4E7} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} {E378A792-A0DE-4BD4-8473-B50EC92209FD} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {23D21D9E-9F29-4ECF-B4D6-690D072E7FF6} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {F2BB1A4A-15B3-4C56-ACDE-BE52B1D000D8} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {B9D94FA6-CEAF-488F-8B1C-CA93C4F999A7} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {2042090B-E2E7-4EC9-8A97-48C4F2013861} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {0884F923-37B8-4728-A3EB-AD28CD38A0B6} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {9D0D0F2F-37BC-485B-AF47-00788E5092A2} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {70C3477B-8A46-480A-AB1D-0DCD486A55AD} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {23253C8E-341C-4613-9834-E7CDBE2D88BA} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {A91AD05D-9BD5-43C3-9A0B-7D0F8CCE0267} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} + {4CAF1FEC-CAC2-44BE-A72B-540877583C36} = {857B6AAC-168B-4C0A-AC0E-9471B1133E18} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8CE0498A-BD84-493A-92FE-9B9AB146D86D} diff --git a/source/Tests/Caching/Unit/AzureBlobResultCacheStoreTests.cs b/source/Tests/Caching/Unit/AzureBlobResultCacheStoreTests.cs index 4b475ce05..aa67fa2a3 100644 --- a/source/Tests/Caching/Unit/AzureBlobResultCacheStoreTests.cs +++ b/source/Tests/Caching/Unit/AzureBlobResultCacheStoreTests.cs @@ -5,22 +5,22 @@ using SourceMock.Internal; using Xunit; using SharpLab.Server.Integration.Azure; -using SharpLab.Server.Monitoring.Mocks; +using SharpLab.Server.Caching.Mocks; -namespace SharpLab.Tests.Caching.Unit { - public class AzureBlobResultCacheStoreTests { - [Fact] - public async Task StoreAsync_DoesNotCallUploadBlobAsync_ForSecondCallWithSameKey() { - // Arrange - var blobContainerMock = new BlobContainerClientMock(); - var store = new AzureBlobResultCacheStore(blobContainerMock, "_", new MonitorMock()); - await store.StoreAsync("test-key", new MemoryStream(), CancellationToken.None); +namespace SharpLab.Tests.Caching.Unit; - // Act - await store.StoreAsync("test-key", new MemoryStream(), CancellationToken.None); +public class AzureBlobResultCacheStoreTests { + [Fact] + public async Task StoreAsync_DoesNotCallUploadBlobAsync_ForSecondCallWithSameKey() { + // Arrange + var blobContainerMock = new BlobContainerClientMock(); + var store = new AzureBlobResultCacheStore(blobContainerMock, "_", new CachingTrackerMock()); + await store.StoreAsync("test-key", new MemoryStream(), CancellationToken.None); - // Assert - Assert.Equal(1, blobContainerMock.Calls.UploadBlobAsync(content: default(MockArgumentMatcher)).Count); - } + // Act + await store.StoreAsync("test-key", new MemoryStream(), CancellationToken.None); + + // Assert + Assert.Equal(1, blobContainerMock.Calls.UploadBlobAsync(content: default(MockArgumentMatcher)).Count); } } diff --git a/source/Tests/Common/Unit/ExceptionLogFilterTests.cs b/source/Tests/Common/Unit/ExceptionLogFilterTests.cs new file mode 100644 index 000000000..4689aed18 --- /dev/null +++ b/source/Tests/Common/Unit/ExceptionLogFilterTests.cs @@ -0,0 +1,35 @@ +using MirrorSharp.Advanced.Mocks; +using SharpLab.Server.Common; +using System; +using Xunit; + +namespace SharpLab.Tests.Common.Unit; + +public class ExceptionLogFilterTests { + [Fact] + public void ShouldLog_ReturnsTrue_ForGeneralException() { + // Arrange + var filter = new ExceptionLogFilter(); + + // Act + var shouldLog = filter.ShouldLog(new Exception(), new WorkSessionMock()); + + // Assert + Assert.True(shouldLog); + } + + [Fact] + public void ShouldLog_ReturnsFalse_ForBadImageFormatException_WithILEmitByte() { + // Arrange + var filter = new ExceptionLogFilter(); + var session = new WorkSessionMock(); + session.Setup.LanguageName.Returns(LanguageNames.IL); + session.Setup.GetText().Returns("ABC .emitbyte DEF"); + + // Act + var shouldLog = filter.ShouldLog(new BadImageFormatException(), session); + + // Assert + Assert.False(shouldLog); + } +} diff --git a/source/Tests/Decompilation/GeneralTests.cs b/source/Tests/Decompilation/GeneralTests.cs index 71b93a7db..466a25822 100644 --- a/source/Tests/Decompilation/GeneralTests.cs +++ b/source/Tests/Decompilation/GeneralTests.cs @@ -6,165 +6,195 @@ using Xunit; using Xunit.Abstractions; -namespace SharpLab.Tests.Decompilation { - public class GeneralTests { - private readonly ITestOutputHelper _output; - - public GeneralTests(ITestOutputHelper output) { - _output = output; - // TestAssemblyLog.Enable(output); - } - - [Theory] - [InlineData("class C { void M((int, string) t) {} }")] // Tuples, https://github.com/ashmind/SharpLab/issues/139 - public async Task SlowUpdate_DecompilesSimpleCodeWithoutErrors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - Assert.True(string.IsNullOrEmpty(errors), errors); - Assert.NotNull(result.ExtensionResult); - Assert.NotEmpty(result.ExtensionResult); - } - - [Theory] - [InlineData("Constructor.BaseCall.cs2cs")] - [InlineData("NullPropagation.ToTernary.cs2cs")] - [InlineData("Simple.cs")] - [InlineData("Simple.vb2cs")] - [InlineData("Module.vb2cs")] - [InlineData("Lambda.CallInArray.cs2cs")] // https://github.com/ashmind/SharpLab/issues/9 - [InlineData("Cast.ExplicitOperatorOnNull.cs2cs")] // https://github.com/ashmind/SharpLab/issues/20 - [InlineData("Goto.TryWhile.cs2cs")] // https://github.com/ashmind/SharpLab/issues/123 - [InlineData("Nullable.OperatorLifting.cs2cs")] // https://github.com/ashmind/SharpLab/issues/159 - [InlineData("Finalizer.Exception.cs")] // https://github.com/ashmind/SharpLab/issues/205 - [InlineData("Parameters.Optional.Decimal.cs2cs")] // https://github.com/ashmind/SharpLab/issues/316 - [InlineData("Unsafe.FixedBuffer.cs2cs")] // https://github.com/ashmind/SharpLab/issues/398 - [InlineData("Switch.String.Large.cs2cs")] - [InlineData("Lock.Simple.cs2cs")] - [InlineData("Property.InitOnly.cs2cs")] - public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) { - var code = await TestCode.FromFileAsync(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(code); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); - } - - [Theory] - [InlineData("Condition.SimpleSwitch.cs")] // https://github.com/ashmind/SharpLab/issues/25 - //[InlineData("Variable.FromArgumentToCall.cs2cs")] // https://github.com/ashmind/SharpLab/issues/128 - [InlineData("Preprocessor.IfDebug.cs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("Preprocessor.IfDebug.vb2cs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("FSharp/Preprocessor.IfDebug.fs")] // https://github.com/ashmind/SharpLab/issues/161 - [InlineData("Using.Simple.cs")] // https://github.com/ashmind/SharpLab/issues/185 - [InlineData("StringInterpolation.Simple.cs")] - public async Task SlowUpdate_ReturnsExpectedDecompiledCode_InDebug(string codeFilePath) { - var data = await TestCode.FromFileAsync(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(data, Optimize.Debug); - - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); - - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - data.AssertIsExpected(decompiledText, _output); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "/// \r\npublic class C {}", "CS1574")] // https://github.com/ashmind/SharpLab/issues/219 - [InlineData(LanguageNames.VisualBasic, "''' \r\nPublic Class C\r\nEnd Class", "BC42309")] - public async Task SlowUpdate_ReturnsExpectedWarnings_ForXmlDocumentation(string sourceLanguageName, string code, string expectedWarningId) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); - - var result = await driver.SendSlowUpdateAsync(); - Assert.Equal( - new[] { new { Severity = "warning", Id = expectedWarningId } }, - result.Diagnostics.Select(d => new { d.Severity, d.Id }).ToArray() - ); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "public class C {}")] - [InlineData(LanguageNames.VisualBasic, "Public Class C\r\nEnd Class")] - public async Task SlowUpdate_DoesNotReturnWarnings_ForCodeWithoutXmlDocumentation(string sourceLanguageName, string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); - - var result = await driver.SendSlowUpdateAsync(); - Assert.Empty(result.Diagnostics); - } - - [Theory] - [InlineData(LanguageNames.CSharp, "class X { class Y: X {Y.Y.Y.Y.Y.Y.Y.Y.Y y; } }")] // https://codegolf.stackexchange.com/a/69200 - [InlineData(LanguageNames.VisualBasic, @" - Class X (Of A, B, C, D, E) - Class Y Inherits X (Of Y, Y, Y, Y, Y) - Private y As Y.Y.Y.Y.Y.Y.Y.Y.Y - End Class - End Class - ")] - public async Task SlowUpdate_ReturnsRoslynGuardException_ForCompilerBombs(string languageName, string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(languageName, TargetNames.IL); - - await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); - } - - [Theory] - [InlineData("x[][][][][]")] - [InlineData("x [,,,] [,] [,,,] [,,,] [,]")] - [InlineData("x [] [] [] [] []")] - [InlineData("x[1][2][3][4][5]")] - [InlineData("x[[[[[][][][][]]]]]")] - [InlineData("x[[[[[[]]]]]]")] - [InlineData("x()()()()()")] - [InlineData("x (,,,) (,) (,,,) (,,,) (,)")] - [InlineData("x () () () () ()")] - [InlineData("x(1)(2)(3)(4)(5)")] - [InlineData("x((((()()()()()))))")] - [InlineData("x(((((())))))")] - public async Task SetOptions_ReturnsRoslynGuardException_ForTextExceedingTokenLimits(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - - await Assert.ThrowsAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); - } - - [Theory] - [InlineData("Append(Append(Append(Append(hash, (byte)value), value>>8), value>>16), value>>24)")] - public async Task SetOptions_ProcessesTokenEdgeCases_WithoutTokenValidationErrors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); - - var exception = await Record.ExceptionAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); - - Assert.Null(exception); - } - - [Fact] // https://github.com/ashmind/SharpLab/issues/817 - public async Task SlowUpdate_DoesNotReportAnyErrors_WhenSwitchingFromTopLevelStatementsToNonTopLevel() { - // Arrange - var code = "class C { void M() {} }"; - var driver = TestEnvironment.NewDriver().SetTextWithCursor(code + "|"); - await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); - // switches to top-level statement mode - await driver.SendTypeCharAsync('+'); - await driver.SendSlowUpdateAsync(); - // switches back (removes + at the end) - await driver.SendBackspaceAsync(); - - // Act - var result = await driver.SendSlowUpdateAsync(); - - // Assert - var errors = result.JoinErrors(); - Assert.True(string.IsNullOrEmpty(errors), errors); - } +namespace SharpLab.Tests.Decompilation; + +public class GeneralTests { + private readonly ITestOutputHelper _output; + + public GeneralTests(ITestOutputHelper output) { + _output = output; + // TestDiagnosticLog.Enable(output); + } + + [Theory] + [InlineData("class C { void M((int, string) t) {} }")] // Tuples, https://github.com/ashmind/SharpLab/issues/139 + public async Task SlowUpdate_DecompilesSimpleCodeWithoutErrors(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + Assert.True(string.IsNullOrEmpty(errors), errors); + Assert.NotNull(result.ExtensionResult); + Assert.NotEmpty(result.ExtensionResult); + } + + [Theory] + [InlineData("Constructor.BaseCall.cs")] + [InlineData("NullPropagation.ToTernary.cs")] + [InlineData("Simple.cs")] + [InlineData("Simple.vb")] + [InlineData("Module.vb")] + [InlineData("Lambda.CallInArray.cs")] // https://github.com/ashmind/SharpLab/issues/9 + [InlineData("Cast.ExplicitOperatorOnNull.cs")] // https://github.com/ashmind/SharpLab/issues/20 + [InlineData("Goto.TryWhile.cs")] // https://github.com/ashmind/SharpLab/issues/123 + [InlineData("Nullable.OperatorLifting.cs")] // https://github.com/ashmind/SharpLab/issues/159 + [InlineData("Finalizer.Exception.cs")] // https://github.com/ashmind/SharpLab/issues/205 + [InlineData("Parameters.Optional.Decimal.cs")] // https://github.com/ashmind/SharpLab/issues/316 + [InlineData("Unsafe.FixedBuffer.cs")] // https://github.com/ashmind/SharpLab/issues/398 + [InlineData("Switch.String.Large.cs")] + [InlineData("Lock.Simple.cs")] + [InlineData("Property.InitOnly.cs")] + [InlineData("Nullable.Reference.Simple.IL.cs")] + [InlineData("Scopes.File.cs")] + public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) { + var code = await TestCode.FromFileAsync(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(code); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await code.AssertIsExpectedAsync(decompiledText, _output); + } + + [Theory] + [InlineData("Condition.SimpleSwitch.cs")] // https://github.com/ashmind/SharpLab/issues/25 + //[InlineData("Variable.FromArgumentToCall.cs2cs")] // https://github.com/ashmind/SharpLab/issues/128 + [InlineData("Preprocessor.IfDebug.cs")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("Preprocessor.IfDebug.vb")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("FSharp/Preprocessor.IfDebug.fs")] // https://github.com/ashmind/SharpLab/issues/161 + [InlineData("Using.Simple.cs")] // https://github.com/ashmind/SharpLab/issues/185 + [InlineData("StringInterpolation.Simple.cs")] + public async Task SlowUpdate_ReturnsExpectedDecompiledCode_InDebug(string codeFilePath) { + var data = await TestCode.FromFileAsync(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(data, Optimize.Debug); + + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); + + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await data.AssertIsExpectedAsync(decompiledText, _output); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "/// \r\npublic class C {}", "CS1574")] // https://github.com/ashmind/SharpLab/issues/219 + [InlineData(LanguageNames.VisualBasic, "''' \r\nPublic Class C\r\nEnd Class", "BC42309")] + public async Task SlowUpdate_ReturnsExpectedWarnings_ForXmlDocumentation(string sourceLanguageName, string code, string expectedWarningId) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); + + var result = await driver.SendSlowUpdateAsync(); + Assert.Contains( + new { Severity = "warning", Id = expectedWarningId }, + result.Diagnostics.Select(d => new { d.Severity, d.Id }).ToArray() + ); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "public class C {}")] + [InlineData(LanguageNames.VisualBasic, "Public Class C\r\nEnd Class")] + public async Task SlowUpdate_DoesNotReturnWarnings_ForCodeWithoutXmlDocumentation(string sourceLanguageName, string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(sourceLanguageName, TargetNames.IL); + + var result = await driver.SendSlowUpdateAsync(); + Assert.DoesNotContain(result.Diagnostics, d => d.Severity is "warning" or "error"); + } + + [Theory] + [InlineData(LanguageNames.CSharp, "CompilerBomb.Generic.1.cs")] + [InlineData(LanguageNames.CSharp, "CompilerBomb.Generic.2.cs")] + [InlineData(LanguageNames.VisualBasic, "CompilerBomb.Generic.vb")] + public async Task SlowUpdate_ReturnsRoslynGuardException_ForCompilerBombs(string languageName, string codeFilePath) { + var code = await TestCode.FromCodeOnlyFileAsync(codeFilePath); + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(languageName, TargetNames.IL); + + await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); + } + + [Fact] // https://github.com/ashmind/SharpLab/issues/1232 + public async Task SlowUpdate_ReturnsRoslynGuardException_ForGenericPointerStackOverflow() { + // TODO: Can be removed once https://github.com/dotnet/roslyn/issues/65594 is resolved + var code = @" + using System.ComponentModel; + class C + { + [DefaultValue(default(C[]>.E))] + enum E { } + } + "; + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL); + + await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); + } + + [Theory] + [InlineData("x[][][][][]")] + [InlineData(";[][][][][] x[][][][][]")] + [InlineData(";[x[][][][][]]")] + [InlineData("x [,,,] [,] [,,,] [,,,] [,]")] + [InlineData("x [] [] [] [] []")] + [InlineData("x[1][2][3][4][5]")] + [InlineData("x[[[[[][][][][]]]]]")] + [InlineData("x[[[[[[]]]]]]")] + [InlineData("x()()()()()")] + [InlineData("x (,,,) (,) (,,,) (,,,) (,)")] + [InlineData("x () () () () ()")] + [InlineData("x(1)(2)(3)(4)(5)")] + [InlineData("x((((()()()()()))))")] + [InlineData("x(((((())))))")] + public async Task SetOptions_ReturnsRoslynGuardException_ForTextExceedingTokenLimits(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + + await Assert.ThrowsAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); + } + + [Theory] + [InlineData("Append(Append(Append(Append(hash, (byte)value), value>>8), value>>16), value>>24)")] + [InlineData("; [Attribute1] [Attribute2] [Attribute3] [Attribute4] [Attribute5]")] + [InlineData("} [Attribute1] [Attribute2] [Attribute3] [Attribute4] [Attribute5]")] + public async Task SetOptions_ProcessesTokenEdgeCases_WithoutTokenValidationErrors(string code) { + var driver = TestEnvironment.NewDriver().SetText(code); + + var exception = await Record.ExceptionAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); + + Assert.Null(exception); + } + + [Theory] + [InlineData("Attributes.TopLevelSequence.cs")] + public async Task SetOptions_ProcessesComplexTokenEdgeCases_WithoutTokenValidationErrors(string codeFilePath) { + var code = await TestCode.FromCodeOnlyFileAsync(codeFilePath); + var driver = TestEnvironment.NewDriver().SetText(code); + + var exception = await Record.ExceptionAsync(() => driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.IL)); + + Assert.Null(exception); + } + + [Fact] // https://github.com/ashmind/SharpLab/issues/817 + public async Task SlowUpdate_DoesNotReportAnyErrors_WhenSwitchingFromTopLevelStatementsToNonTopLevel() { + // Arrange + var code = "class C { void M() {} }"; + var driver = TestEnvironment.NewDriver().SetTextWithCursor(code + "|"); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.CSharp); + // switches to top-level statement mode + await driver.SendTypeCharAsync('+'); + await driver.SendSlowUpdateAsync(); + // switches back (removes + at the end) + await driver.SendBackspaceAsync(); + + // Act + var result = await driver.SendSlowUpdateAsync(); + + // Assert + var errors = result.JoinErrors(); + Assert.True(string.IsNullOrEmpty(errors), errors); } } diff --git a/source/Tests/Decompilation/LanguageFSharpTests.cs b/source/Tests/Decompilation/LanguageFSharpTests.cs index 636dc1573..972ad9c14 100644 --- a/source/Tests/Decompilation/LanguageFSharpTests.cs +++ b/source/Tests/Decompilation/LanguageFSharpTests.cs @@ -3,30 +3,30 @@ using Xunit.Abstractions; using SharpLab.Tests.Internal; -namespace SharpLab.Tests.Decompilation { - public class LanguageFSharpTests { - private readonly ITestOutputHelper _output; +namespace SharpLab.Tests.Decompilation; - public LanguageFSharpTests(ITestOutputHelper output) { - _output = output; - // TestAssemblyLog.Enable(output); - } +public class LanguageFSharpTests { + private readonly ITestOutputHelper _output; - [Theory] - [InlineData("FSharp/EmptyType.fs")] - [InlineData("FSharp/SimpleMethod.fs2cs")] // https://github.com/ashmind/SharpLab/issues/119 - [InlineData("FSharp/NotNull.fs2cs")] - [InlineData("FSharp/SimpleUnion.fs")] - public async Task SlowUpdate_ReturnsExpectedDecompiledCode_ForFSharp(string codeFilePath) { - var code = await TestCode.FromFileAsync(codeFilePath); - var driver = await TestDriverFactory.FromCodeAsync(code); + public LanguageFSharpTests(ITestOutputHelper output) { + _output = output; + // TestDiagnosticLog.Enable(output); + } + + [Theory] + [InlineData("FSharp/EmptyType.fs")] + [InlineData("FSharp/SimpleMethod.fs")] // https://github.com/ashmind/SharpLab/issues/119 + [InlineData("FSharp/NotNull.fs")] + [InlineData("FSharp/SimpleUnion.fs")] + public async Task SlowUpdate_ReturnsExpectedDecompiledCode_ForFSharp(string codeFilePath) { + var code = await TestCode.FromFileAsync(codeFilePath); + var driver = await TestDriverFactory.FromCodeAsync(code); - var result = await driver.SendSlowUpdateAsync(); - var errors = result.JoinErrors(); + var result = await driver.SendSlowUpdateAsync(); + var errors = result.JoinErrors(); - var decompiledText = result.ExtensionResult?.Trim(); - Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); - } + var decompiledText = result.ExtensionResult?.Trim(); + Assert.True(string.IsNullOrEmpty(errors), errors); + await code.AssertIsExpectedAsync(decompiledText, _output); } } diff --git a/source/Tests/Decompilation/LanguageILTests.cs b/source/Tests/Decompilation/LanguageILTests.cs index a1c183d4b..2ba9b2714 100644 --- a/source/Tests/Decompilation/LanguageILTests.cs +++ b/source/Tests/Decompilation/LanguageILTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.IO; using System; +using Mobius.ILasm.Core; namespace SharpLab.Tests.Decompilation { public class LanguageILTests { @@ -13,7 +14,7 @@ public class LanguageILTests { public LanguageILTests(ITestOutputHelper output) { _output = output; - // TestAssemblyLog.Enable(output); + // TestDiagnosticLog.Enable(output); } [Theory] @@ -28,7 +29,7 @@ public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) var decompiledText = result.ExtensionResult?.Trim(); Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); + await code.AssertIsExpectedAsync(decompiledText, _output); } [Theory] @@ -59,12 +60,12 @@ instance void M() cil managed ); } - [Fact] - public async Task SlowUpdate_ReturnsUnsupportedWarningDiagnostic_ForAnyPermissionSet() { + [Theory] + [InlineData(".assembly _ { .permissionset reqmin = () }")] + [InlineData(".assembly _ { .permissionset reqmin = ( 01 ) }")] + public async Task SlowUpdate_ReturnsUnsupportedWarningDiagnostic_ForAnyPermissionSet(string code) { // Arrange - var driver = await TestDriverFactory.FromCodeAsync(@" - .assembly _ { .permissionset reqmin = ( 01 ) } - ", LanguageNames.IL, TargetNames.IL); + var driver = await TestDriverFactory.FromCodeAsync(code, LanguageNames.IL, TargetNames.IL); // Act var result = await driver.SendSlowUpdateAsync(); @@ -284,5 +285,26 @@ .method void M() cil managed result.Diagnostics.Select(d => (d.Severity, d.Id, d.Message)).ToArray() ); } + + [Fact] + public async Task SlowUpdate_ReportsErrorDiagnostic_ForUndeclaredParameterReference_WithUnnamedParameter() { + // Arrange + var driver = await TestDriverFactory.FromCodeAsync(""" + .method void M(int16) cil managed + { + ldarg x + pop + } + """, LanguageNames.IL, TargetNames.IL); + + // Act + var result = await driver.SendSlowUpdateAsync(); + + // Assert + Assert.Equal( + new[] { ("error", "IL", "Undeclared identifier 'x'") }, + result.Diagnostics.Select(d => (d.Severity, d.Id, d.Message)).ToArray() + ); + } } } diff --git a/source/Tests/Decompilation/TargetAstTests.cs b/source/Tests/Decompilation/TargetAstTests.cs index efff173ad..b94bfe5d6 100644 --- a/source/Tests/Decompilation/TargetAstTests.cs +++ b/source/Tests/Decompilation/TargetAstTests.cs @@ -10,13 +10,13 @@ public class TargetAstTests { public TargetAstTests(ITestOutputHelper output) { _output = output; - // TestAssemblyLog.Enable(output); + // TestDiagnosticLog.Enable(output); } [Theory] - [InlineData("Ast/EmptyClass.cs2ast")] - [InlineData("Ast/StructuredTrivia.cs2ast")] - [InlineData("Ast/LiteralTokens.cs2ast")] + [InlineData("Ast/EmptyClass.cs")] + [InlineData("Ast/StructuredTrivia.cs")] + [InlineData("Ast/LiteralTokens.cs")] [InlineData("Ast/EmptyType.fs")] [InlineData("Ast/LiteralTokens.fs")] public async Task SlowUpdate_ReturnsExpectedResult(string codeFilePath) { @@ -27,7 +27,7 @@ public async Task SlowUpdate_ReturnsExpectedResult(string codeFilePath) { var json = result.ExtensionResult?.ToString(); - code.AssertIsExpected(json, _output); + await code.AssertIsExpectedAsync(json, _output); } } } diff --git a/source/Tests/Decompilation/TargetJitAsmTests.cs b/source/Tests/Decompilation/TargetJitAsmTests.cs index dd13d6fef..71dd3cfe9 100644 --- a/source/Tests/Decompilation/TargetJitAsmTests.cs +++ b/source/Tests/Decompilation/TargetJitAsmTests.cs @@ -1,5 +1,4 @@ using System; -using System.Runtime.Intrinsics.X86; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -13,20 +12,20 @@ public class TargetJitAsmTests { public TargetJitAsmTests(ITestOutputHelper output) { _output = output; - // TestAssemblyLog.Enable(output); + // TestDiagnosticLog.Enable(output); } [Theory] - [InlineData("JitAsm/Simple.cs2asm")] - [InlineData("JitAsm/MultipleReturns.cs2asm")] - [InlineData("JitAsm/ArrayElement.cs2asm")] - [InlineData("JitAsm/AsyncRegression.cs2asm")] - [InlineData("JitAsm/ConsoleWrite.cs2asm")] - [InlineData("JitAsm/JumpBack.cs2asm")] // https://github.com/ashmind/SharpLab/issues/229 - [InlineData("JitAsm/Delegate.cs2asm")] - [InlineData("JitAsm/Nested.Simple.cs2asm")] - [InlineData("JitAsm/Generic.Open.Multiple.cs2asm")] - [InlineData("JitAsm/Generic.MethodWithAttribute.cs2asm")] + [InlineData("JitAsm/Simple.cs")] + [InlineData("JitAsm/MultipleReturns.cs")] + [InlineData("JitAsm/ArrayElement.cs")] + [InlineData("JitAsm/AsyncRegression.cs")] + [InlineData("JitAsm/ConsoleWrite.cs")] + [InlineData("JitAsm/JumpBack.cs")] // https://github.com/ashmind/SharpLab/issues/229 + [InlineData("JitAsm/Delegate.cs")] + [InlineData("JitAsm/Nested.Simple.cs")] + [InlineData("JitAsm/Generic.Open.Multiple.cs")] + [InlineData("JitAsm/Generic.MethodWithAttribute.cs")] [InlineData("JitAsm/Generic.ClassWithAttribute.cs")] // TODO: Diagnose later // [InlineData("JitAsm/Generic.MethodWithAttribute.fs2asm")] @@ -34,15 +33,10 @@ public TargetJitAsmTests(ITestOutputHelper output) { [InlineData("JitAsm/Generic.Nested.AttributeOnNested.cs")] [InlineData("JitAsm/Generic.Nested.AttributeOnBoth.cs")] [InlineData("JitAsm/Vectors.Avx2.cs")] - [InlineData("JitAsm/Math.FusedMultiplyAdd.Fma.cs2asm")] + [InlineData("JitAsm/Math.FusedMultiplyAdd.cs")] [InlineData("JitAsm/DllImport.cs")] // https://github.com/ashmind/SharpLab/issues/666 + [InlineData("JitAsm/MethodImpl.InternalCall.cs")] // https://github.com/ashmind/SharpLab/issues/752 public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) { - // https://github.com/ashmind/SharpLab/issues/514 - if (codeFilePath.Contains(".Fma.") && !Fma.IsSupported) - codeFilePath = codeFilePath.Replace(".Fma.", ".NoFma."); - if (codeFilePath.Contains(".Avx2.") && !Avx2.IsSupported) - codeFilePath = codeFilePath.Replace(".Avx2.", ".NoAvx2."); - var code = await TestCode.FromFileAsync(codeFilePath); var driver = await TestDriverFactory.FromCodeAsync(code); @@ -51,18 +45,51 @@ public async Task SlowUpdate_ReturnsExpectedDecompiledCode(string codeFilePath) var decompiledText = result.ExtensionResult?.Trim(); Assert.True(string.IsNullOrEmpty(errors), errors); - code.AssertIsExpected(decompiledText, _output); + await code.AssertIsExpectedAsync(decompiledText, _output); } [Theory] - [InlineData("class C { static int F = 1; }")] - [InlineData("class C { static C() {} }")] - [InlineData("class C { class N { static N() {} } }")] + [InlineData("class C { static int F = ((Func)(() => throw new ConstructorRanException()))(); }")] + [InlineData("class C { static C() => throw new ConstructorRanException(); }")] + [InlineData("class C { class N { static N() => throw new ConstructorRanException(); } }")] public async Task SlowUpdate_ReturnsNotSupportedError_ForStaticConstructors(string code) { - var driver = TestEnvironment.NewDriver().SetText(code); + var driver = TestEnvironment.NewDriver().SetText(@$" + using System; + public class ConstructorRanException: Exception {{}} + + {code} + "); + await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.JitAsm); + + var (result, exception) = await RecordExceptionOrResultAsync(() => driver.SendSlowUpdateAsync()); + + Assert.Empty(result?.JoinErrors() ?? ""); + Assert.IsType(exception); + } + + [Theory] + [InlineData("class C { [ModuleInitializer] public static void I() => throw new InitializerRanException(); }")] + [InlineData("class C { public class N { [ModuleInitializer] public static void I() => throw new InitializerRanException(); } }")] + [InlineData(@" + class C { [ModuleInitializer] public static void I() => throw new InitializerRanException(); } + namespace System.Runtime.CompilerServices { + public class ModuleInitializerAttribute : Attribute {} + } + ")] + public async Task SlowUpdate_ReturnsNotSupportedError_ForModuleInitializers(string code) { + var driver = TestEnvironment.NewDriver().SetText(@$" + using System; + using System.Runtime.CompilerServices; + public class InitializerRanException: Exception {{}} + + {code} + "); await driver.SendSetOptionsAsync(LanguageNames.CSharp, TargetNames.JitAsm); - await Assert.ThrowsAsync(() => driver.SendSlowUpdateAsync()); + var (result, exception) = await RecordExceptionOrResultAsync(() => driver.SendSlowUpdateAsync()); + + Assert.Empty(result?.JoinErrors() ?? ""); + Assert.IsType(exception); } [Theory] @@ -82,5 +109,14 @@ public async Task SlowUpdate_ReturnsJitGenericAttributeException_ForIncorrectJit Assert.IsType(exception); } + + private async Task<(T? result, Exception? exception)> RecordExceptionOrResultAsync(Func> callAsync) { + try { + return (await callAsync(), null); + } + catch (Exception ex) { + return (default, ex); + } + } } } diff --git a/source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs2ast b/source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs similarity index 94% rename from source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs2ast rename to source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs index 69aae3af6..b9c6b19f0 100644 --- a/source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs2ast +++ b/source/Tests/Decompilation/TestCode/Ast/EmptyClass.cs @@ -1,7 +1,7 @@ -public class C { +public class C { } -#=> +/* ast [ { @@ -109,3 +109,4 @@ } ] +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Ast/EmptyType.fs b/source/Tests/Decompilation/TestCode/Ast/EmptyType.fs index 58d0ff6ef..1fb65e0a5 100644 --- a/source/Tests/Decompilation/TestCode/Ast/EmptyType.fs +++ b/source/Tests/Decompilation/TestCode/Ast/EmptyType.fs @@ -7,6 +7,63 @@ type Empty = class end "kind": "ParsedImplFileInput", "type": "node", "children": [ + { + "kind": "SynModuleOrNamespace", + "type": "node", + "range": "0-22", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "_", + "range": "0-0" + }, + { + "kind": "SynModuleDecl.Types", + "type": "node", + "range": "0-22", + "children": [ + { + "kind": "SynTypeDefn", + "type": "node", + "range": "5-22", + "children": [ + { + "kind": "SynComponentInfo", + "property": "typeInfo", + "type": "node", + "range": "5-10", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "Empty", + "range": "5-10" + } + ] + }, + { + "kind": "SynTypeDefnRepr.ObjectModel", + "property": "typeRepr", + "type": "node", + "range": "13-22", + "children": [ + { + "kind": "SynTypeDefnKind", + "property": "kind", + "type": "node", + "value": "Class" + } + ] + } + ] + } + ] + } + ] + }, { "kind": "SynModuleOrNamespace", "type": "node", diff --git a/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs2ast b/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs similarity index 97% rename from source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs2ast rename to source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs index 957612534..deadb96b6 100644 --- a/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs2ast +++ b/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.cs @@ -9,7 +9,7 @@ class C { object o = null; } -#=> +/* ast [ { @@ -873,4 +873,6 @@ class C { } ] } -] \ No newline at end of file +] + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs b/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs index 1fb92d4ea..fef785f47 100644 --- a/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs +++ b/source/Tests/Decompilation/TestCode/Ast/LiteralTokens.fs @@ -23,15 +23,10 @@ b" "range": "0-0" }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "0-1", "children": [ - { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, { "kind": "SynExpr.Const", "property": "expr", @@ -49,15 +44,10 @@ b" ] }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "3-6", "children": [ - { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, { "kind": "SynExpr.Const", "property": "expr", @@ -75,15 +65,95 @@ b" ] }, { - "kind": "SynModuleDecl.DoExpr", + "kind": "SynModuleDecl.Expr", "type": "node", "range": "8-14", "children": [ { - "kind": "DebugPointAtBinding.Yes", - "property": "debugPoint", - "type": "node" - }, + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "8-14", + "children": [ + { + "kind": "SynConst.String", + "property": "constant", + "type": "token", + "value": "\"a\r\nb\"", + "children": [ + { + "kind": "SynStringKind", + "property": "synStringKind", + "type": "value", + "value": "Regular" + } + ] + } + ] + } + ] + } + ] + }, + { + "kind": "SynModuleOrNamespace", + "type": "node", + "range": "0-14", + "children": [ + { + "type": "token", + "kind": "Ident", + "property": "longId", + "value": "_", + "range": "0-0" + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "0-1", + "children": [ + { + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "0-1", + "children": [ + { + "kind": "SynConst.Int32", + "property": "constant", + "type": "token", + "value": "1" + } + ] + } + ] + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "3-6", + "children": [ + { + "kind": "SynExpr.Const", + "property": "expr", + "type": "node", + "range": "3-6", + "children": [ + { + "kind": "SynConst.Char", + "property": "constant", + "type": "token", + "value": "'c'" + } + ] + } + ] + }, + { + "kind": "SynModuleDecl.Expr", + "type": "node", + "range": "8-14", + "children": [ { "kind": "SynExpr.Const", "property": "expr", diff --git a/source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs2ast b/source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs similarity index 96% rename from source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs2ast rename to source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs index 2a4ba2c3c..773c47086 100644 --- a/source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs2ast +++ b/source/Tests/Decompilation/TestCode/Ast/StructuredTrivia.cs @@ -1,7 +1,7 @@ -/// Test +/// Test + +/* ast -#=> - [ { "type": "node", @@ -164,4 +164,6 @@ } ] } -] \ No newline at end of file +] + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Attributes.TopLevelSequence.cs b/source/Tests/Decompilation/TestCode/Attributes.TopLevelSequence.cs new file mode 100644 index 000000000..3d50326f0 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/Attributes.TopLevelSequence.cs @@ -0,0 +1,11 @@ +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security; +using System.Security.Permissions; + +[assembly: CompilationRelaxations(8)] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] +[assembly: AssemblyVersion("0.0.0.0")] \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs b/source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs similarity index 89% rename from source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs rename to source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs index 2c12eae59..7de021acb 100644 --- a/source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs2cs +++ b/source/Tests/Decompilation/TestCode/Cast.ExplicitOperatorOnNull.cs @@ -8,7 +8,7 @@ public void Baz() { } } -#=> +/* cs using System; using System.Diagnostics; @@ -23,17 +23,23 @@ public void Baz() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class Foo { + [NullableContext(1)] public static explicit operator Nullable(Foo foo) { return 1u; } } + public class Bar { public void Baz() { Nullable num = (Nullable)(Foo)null; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.1.cs b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.1.cs new file mode 100644 index 000000000..4a59e0b69 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.1.cs @@ -0,0 +1,4 @@ +// https://codegolf.stackexchange.com/a/69200 +class X { + class Y : X { Y.Y.Y.Y.Y.Y.Y.Y.Y y; } +} \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.2.cs b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.2.cs new file mode 100644 index 000000000..552fa7e91 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.2.cs @@ -0,0 +1,10 @@ +// https://github.com/ashmind/SharpLab/issues/1223 +class Z { + class X : Z< + Z, X, X, X>, + Z, + Z, + Z> { + class Y : X.X.X.X { } + } +} \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.vb b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.vb new file mode 100644 index 000000000..cbf594aeb --- /dev/null +++ b/source/Tests/Decompilation/TestCode/CompilerBomb.Generic.vb @@ -0,0 +1,5 @@ +Class X(Of A, B, C, D, E) + Class Y Inherits X (Of Y, Y, Y, Y, Y) + Private y As Y.Y.Y.Y.Y.Y.Y.Y.Y + End Class +End Class \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs b/source/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs index 7f779ea8d..addc434da 100644 --- a/source/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs +++ b/source/Tests/Decompilation/TestCode/Condition.SimpleSwitch.cs @@ -20,8 +20,11 @@ public void M(string n) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { + [NullableContext(1)] public void M(string n) { if (n == "foo") diff --git a/source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs b/source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs similarity index 85% rename from source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs rename to source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs index da361a8a9..03a189696 100644 --- a/source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs2cs +++ b/source/Tests/Decompilation/TestCode/Constructor.BaseCall.cs @@ -9,7 +9,7 @@ public MyClass(string name) : base(name) { } } -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -23,16 +23,23 @@ public MyClass(string name) : base(name) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class MyBase { + [NullableContext(1)] public MyBase(string name) { } } + public class MyClass : MyBase { + [NullableContext(1)] public MyClass(string name) : base(name) { } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/FSharp/EmptyType.fs b/source/Tests/Decompilation/TestCode/FSharp/EmptyType.fs index 635859af3..e12b6e886 100644 --- a/source/Tests/Decompilation/TestCode/FSharp/EmptyType.fs +++ b/source/Tests/Decompilation/TestCode/FSharp/EmptyType.fs @@ -12,12 +12,12 @@ type Empty = class end } .class private auto ansi '' - extends [System.Runtime]System.Object + extends [netstandard]System.Object { } // end of class .class public auto ansi abstract sealed _ - extends [System.Runtime]System.Object + extends [netstandard]System.Object { .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationMappingAttribute::.ctor(valuetype [FSharp.Core]Microsoft.FSharp.Core.SourceConstructFlags) = ( 01 00 07 00 00 00 00 00 @@ -35,8 +35,20 @@ type Empty = class end } // end of class _ .class private auto ansi abstract sealed '.$_' - extends [System.Runtime]System.Object + extends [netstandard]System.Object { + // Methods + .method public static + void main@ () cil managed + { + // Method begins at RVA 0x2050 + // Code size 1 (0x1) + .maxstack 8 + .entrypoint + + IL_0000: ret + } // end of method $_::main@ + } // end of class .$_ *) \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs b/source/Tests/Decompilation/TestCode/FSharp/NotNull.fs similarity index 85% rename from source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs rename to source/Tests/Decompilation/TestCode/FSharp/NotNull.fs index c8e7fb69a..1bdf95b1a 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/FSharp/NotNull.fs2cs +++ b/source/Tests/Decompilation/TestCode/FSharp/NotNull.fs @@ -3,7 +3,7 @@ open System type C() = member __.notNull x = not (isNull x) -#=> +(* cs using System; using System.Reflection; @@ -11,6 +11,7 @@ using Microsoft.FSharp.Core; [assembly: FSharpInterfaceDataVersion(2, 0, 0)] [assembly: AssemblyVersion("0.0.0.0")] + [CompilationMapping(SourceConstructFlags.Module)] public static class @_ { @@ -28,9 +29,15 @@ public static class @_ } } } + namespace { internal static class $_ { + public static void main@() + { + } } -} \ No newline at end of file +} + +*) \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs b/source/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs index a472c65db..b72a4c0a4 100644 --- a/source/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs +++ b/source/Tests/Decompilation/TestCode/FSharp/Preprocessor.IfDebug.fs @@ -6,44 +6,32 @@ (* cs -using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; -using ; using Microsoft.FSharp.Core; [assembly: FSharpInterfaceDataVersion(2, 0, 0)] [assembly: AssemblyVersion("0.0.0.0")] + [CompilationMapping(SourceConstructFlags.Module)] public static class @_ { - [CompilationMapping(SourceConstructFlags.Value)] - internal static PrintfFormat format@1 - { - get - { - return $_.format@1; - } - } } + namespace { internal static class $_ { - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - internal static readonly PrintfFormat format@1; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] [CompilerGenerated] [DebuggerNonUserCode] internal static int init@; - static $_() + public static void main@() { - format@1 = new PrintfFormat("Debug"); - PrintfModule.PrintFormatLineToTextWriter(Console.Out, @_.format@1); + ExtraTopLevelOperators.PrintFormatLine(new PrintfFormat("Debug")); } } } diff --git a/source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs b/source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs similarity index 83% rename from source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs rename to source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs index 9df9c2fab..31bf101b0 100644 --- a/source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs2cs +++ b/source/Tests/Decompilation/TestCode/FSharp/SimpleMethod.fs @@ -2,7 +2,7 @@ open System type C() = member this.M() = 5 -#=> +(* cs using System; using System.Reflection; @@ -10,6 +10,7 @@ using Microsoft.FSharp.Core; [assembly: FSharpInterfaceDataVersion(2, 0, 0)] [assembly: AssemblyVersion("0.0.0.0")] + [CompilationMapping(SourceConstructFlags.Module)] public static class @_ { @@ -23,9 +24,15 @@ public static class @_ } } } + namespace { internal static class $_ { + public static void main@() + { + } } -} \ No newline at end of file +} + +*) \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/FSharp/SimpleUnion.fs b/source/Tests/Decompilation/TestCode/FSharp/SimpleUnion.fs index 1bc668abb..516f7fa5e 100644 --- a/source/Tests/Decompilation/TestCode/FSharp/SimpleUnion.fs +++ b/source/Tests/Decompilation/TestCode/FSharp/SimpleUnion.fs @@ -6,7 +6,8 @@ type T = override x.Equals other = false (* asm -; Core CLR on amd64 + +; Core CLR on x64 _+T..ctor() L0000: ret @@ -26,114 +27,64 @@ _+T.__DebugDisplay() L0004: push rbp L0005: push rbx L0006: sub rsp, 0x20 - L000a: mov rsi, rcx + L000a: mov rbx, rcx L000d: mov rcx, 0x L0017: call 0x - L001c: mov rdi, rax - L001f: mov rdx, 0x - L0029: mov rdx, [rdx] - L002c: lea rcx, [rdi+8] + L001c: mov rsi, rax + L001f: mov rcx, 0x + L0029: mov rdx, [rcx] + L002c: lea rcx, [rsi+8] L0030: call 0x L0035: xor edx, edx - L0037: mov [rdi+0x10], rdx - L003b: mov [rdi+0x18], rdx - L003f: mov rdx, rdi + L0037: mov [rsi+0x10], rdx + L003b: mov [rsi+0x18], rdx + L003f: mov rdx, rsi L0042: mov rcx, 0x - L004c: call Microsoft.FSharp.Core.PrintfImpl+Cache`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetParser(Microsoft.FSharp.Core.PrintfFormat`4) - L0051: mov rbx, rax - L0054: mov rbp, [rdi+0x10] - L0058: test rbp, rbp - L005b: jne short L0069 - L005d: mov rcx, rbx - L0060: cmp [rcx], ecx - L0062: call Microsoft.FSharp.Core.PrintfImpl+FormatParser`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetCurriedStringPrinter() - L0067: jmp short L00a4 - L0069: mov rcx, rbx - L006c: cmp [rcx], ecx - L006e: call Microsoft.FSharp.Core.PrintfImpl+FormatParser`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetStepsForCapturedFormat() - L0073: mov r14, rax - L0076: mov ecx, [rbx+0x28] - L0079: call Microsoft.FSharp.Core.PrintfImpl.StringPrintfEnv(Int32) - L007e: mov rcx, rax - L0081: mov r8, [rdi+0x18] - L0085: mov rdx, rbp - L0088: mov r9, r14 - L008b: cmp [rcx], ecx - L008d: call Microsoft.FSharp.Core.PrintfImpl+PrintfEnv`3[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].RunSteps(System.Object[], System.Type[], Step[]) - L0092: mov rdx, rax - L0095: mov rcx, 0x - L009f: call Microsoft.FSharp.Core.LanguagePrimitives+IntrinsicFunctions.UnboxGeneric[[System.__Canon, System.Private.CoreLib]](System.Object) - L00a4: movsx rdx, byte ptr [rsi] - L00a8: mov rcx, rax - L00ab: mov rax, [rax] - L00ae: mov rax, [rax+0x40] - L00b2: mov rax, [rax+0x20] - L00b6: add rsp, 0x20 - L00ba: pop rbx - L00bb: pop rbp - L00bc: pop rsi - L00bd: pop rdi - L00be: pop r14 - L00c0: jmp rax + L004c: call qword ptr [0x] + L0052: mov rdi, rax + L0055: mov rbp, [rsi+0x10] + L0059: test rbp, rbp + L005c: jne short L0084 + L005e: mov rcx, rdi + L0061: cmp [rcx], ecx + L0063: call qword ptr [0x] + L0069: movzx edx, byte ptr [rbx] + L006c: mov rcx, rax + L006f: mov rax, [rax] + L0072: mov rax, [rax+0x40] + L0076: add rsp, 0x20 + L007a: pop rbx + L007b: pop rbp + L007c: pop rsi + L007d: pop rdi + L007e: pop r14 + L0080: jmp qword ptr [rax+0x20] + L0084: mov rcx, rdi + L0087: cmp [rcx], ecx + L0089: call qword ptr [0x] + L008f: mov r14, rax + L0092: mov ecx, [rdi+0x28] + L0095: call qword ptr [0x] + L009b: mov rcx, rax + L009e: mov r8, [rsi+0x18] + L00a2: mov rdx, rbp + L00a5: mov r9, r14 + L00a8: cmp [rcx], ecx + L00aa: call qword ptr [0x] + L00b0: mov rdx, rax + L00b3: mov rcx, 0x + L00bd: call qword ptr [0x] + L00c3: jmp short L0069 _+T.ToString() - L0000: push r14 - L0002: push rdi - L0003: push rsi - L0004: push rbp - L0005: push rbx - L0006: sub rsp, 0x20 - L000a: mov rsi, rcx - L000d: mov rcx, 0x - L0017: call 0x - L001c: mov rdi, rax - L001f: mov rdx, 0x - L0029: mov rdx, [rdx] - L002c: lea rcx, [rdi+8] - L0030: call 0x - L0035: xor edx, edx - L0037: mov [rdi+0x10], rdx - L003b: mov [rdi+0x18], rdx - L003f: mov rdx, rdi - L0042: mov rcx, 0x - L004c: call Microsoft.FSharp.Core.PrintfImpl+Cache`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetParser(Microsoft.FSharp.Core.PrintfFormat`4) - L0051: mov rbx, rax - L0054: mov rbp, [rdi+0x10] - L0058: test rbp, rbp - L005b: jne short L0069 - L005d: mov rcx, rbx - L0060: cmp [rcx], ecx - L0062: call Microsoft.FSharp.Core.PrintfImpl+FormatParser`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetCurriedStringPrinter() - L0067: jmp short L00a4 - L0069: mov rcx, rbx - L006c: cmp [rcx], ecx - L006e: call Microsoft.FSharp.Core.PrintfImpl+FormatParser`4[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].GetStepsForCapturedFormat() - L0073: mov r14, rax - L0076: mov ecx, [rbx+0x28] - L0079: call Microsoft.FSharp.Core.PrintfImpl.StringPrintfEnv(Int32) - L007e: mov rcx, rax - L0081: mov r8, [rdi+0x18] - L0085: mov rdx, rbp - L0088: mov r9, r14 - L008b: cmp [rcx], ecx - L008d: call Microsoft.FSharp.Core.PrintfImpl+PrintfEnv`3[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].RunSteps(System.Object[], System.Type[], Step[]) - L0092: mov rdx, rax - L0095: mov rcx, 0x - L009f: call Microsoft.FSharp.Core.LanguagePrimitives+IntrinsicFunctions.UnboxGeneric[[System.__Canon, System.Private.CoreLib]](System.Object) - L00a4: movsx rdx, byte ptr [rsi] - L00a8: mov rcx, rax - L00ab: mov rax, [rax] - L00ae: mov rax, [rax+0x40] - L00b2: mov rax, [rax+0x20] - L00b6: add rsp, 0x20 - L00ba: pop rbx - L00bb: pop rbp - L00bc: pop rsi - L00bd: pop rdi - L00be: pop r14 - L00c0: jmp rax + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +_+T.Equals(...) + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +.$_.main@() + L0000: ret -_+T.Equals(System.Object) - L0000: xor eax, eax - L0002: ret *) \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Finalizer.Exception.cs b/source/Tests/Decompilation/TestCode/Finalizer.Exception.cs index b9617f533..cb4139688 100644 --- a/source/Tests/Decompilation/TestCode/Finalizer.Exception.cs +++ b/source/Tests/Decompilation/TestCode/Finalizer.Exception.cs @@ -25,7 +25,7 @@ 69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e 53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69 6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73 74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72 - 73 69 6f 6e 3d 36 2e 30 2e 30 2e 30 2c 20 43 75 + 73 69 6f 6e 3d 39 2e 30 2e 30 2e 30 2c 20 43 75 6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30 33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01 diff --git a/source/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs b/source/Tests/Decompilation/TestCode/Goto.TryWhile.cs similarity index 91% rename from source/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs rename to source/Tests/Decompilation/TestCode/Goto.TryWhile.cs index b74263777..673b0ca47 100644 --- a/source/Tests/Decompilation/TestCode/Goto.TryWhile.cs2cs +++ b/source/Tests/Decompilation/TestCode/Goto.TryWhile.cs @@ -10,7 +10,7 @@ void M() { } } -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -24,6 +24,8 @@ void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { private void M() @@ -41,4 +43,6 @@ private void M() } } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs similarity index 79% rename from source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs index 4f5d5749a..0c1961672 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/ArrayElement.cs @@ -4,9 +4,9 @@ static int M(int[] x) { } } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C.M(Int32[]) L0000: sub rsp, 0x28 @@ -16,4 +16,6 @@ static int M(int[] x) { L000d: add rsp, 0x28 L0011: ret L0012: call 0x - L0017: int3 \ No newline at end of file + L0017: int3 + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs b/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs new file mode 100644 index 000000000..448e9f046 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs @@ -0,0 +1,62 @@ +// https://github.com/ashmind/SharpLab/issues/39#issuecomment-298152571 +using System; +using System.Threading.Tasks; +using System.Runtime.CompilerServices; + +static class C { + static int M(int x) { + return Foo(x + 0x12345).Result; + } + + static async Task Foo(int x) { + return x; + } +} + +/* asm + +; Core CLR on x64 + +C.M(Int32) + L0000: sub rsp, 0x28 + L0004: add ecx, 0x12345 + L000a: call 0x + L000f: mov rcx, rax + L0012: mov eax, [rcx+0x34] + L0015: and eax, 0x + L001a: cmp eax, 0x + L001f: jne short L0029 + L0021: mov eax, [rcx+0x38] + L0024: add rsp, 0x28 + L0028: ret + L0029: mov edx, 1 + L002e: add rsp, 0x28 + L0032: jmp qword ptr [0x] + +C.Foo(Int32) + L0000: sub rsp, 0x38 + L0004: xor eax, eax + L0006: mov [rsp+0x28], rax + L000b: mov [rsp+0x30], rax + L0010: mov [rsp+0x2c], ecx + L0014: mov dword ptr [rsp+0x28], 0x + L001c: lea rcx, [rsp+0x28] + L0021: call 0x + L0026: mov rax, [rsp+0x30] + L002b: test rax, rax + L002e: je short L0035 + L0030: add rsp, 0x38 + L0034: ret + L0035: lea rcx, [rsp+0x30] + L003a: call qword ptr [0x] + L0040: jmp short L0030 + +C+d__1.MoveNext() + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +C+d__1.SetStateMachine(...) + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm deleted file mode 100644 index 3bcc73cf5..000000000 --- a/source/Tests/Decompilation/TestCode/JitAsm/AsyncRegression.cs2asm +++ /dev/null @@ -1,159 +0,0 @@ -// https://github.com/ashmind/SharpLab/issues/39#issuecomment-298152571 -using System; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; - -static class C { - static int M(int x) { - return Foo(x + 0x12345).Result; - } - - static async Task Foo(int x) { - return x; - } -} - -#=> - -; Core CLR on amd64 - -C.M(Int32) - L0000: push rdi - L0001: push rsi - L0002: sub rsp, 0x28 - L0006: add ecx, 0x12345 - L000c: call C.Foo(Int32) - L0011: mov rsi, rax - L0014: mov ecx, [rsi+0x34] - L0017: and ecx, 0x - L001d: cmp ecx, 0x - L0023: jne short L002a - L0025: mov eax, [rsi+0x38] - L0028: jmp short L0076 - L002a: mov ecx, [rsi+0x34] - L002d: test ecx, 0x - L0033: jne short L0045 - L0035: mov rcx, rsi - L0038: xor r8d, r8d - L003b: mov edx, 0x - L0040: call System.Threading.Tasks.Task.InternalWaitCore(Int32, System.Threading.CancellationToken) - L0045: mov rcx, rsi - L0048: call System.Threading.Tasks.Task.NotifyDebuggerOfWaitCompletionIfNecessary() - L004d: mov ecx, [rsi+0x34] - L0050: and ecx, 0x - L0056: cmp ecx, 0x - L005c: je short L0073 - L005e: mov rcx, rsi - L0061: mov edx, 1 - L0066: call System.Threading.Tasks.Task.GetExceptions(Boolean) - L006b: mov rdi, rax - L006e: test rdi, rdi - L0071: jne short L007d - L0073: mov eax, [rsi+0x38] - L0076: add rsp, 0x28 - L007a: pop rsi - L007b: pop rdi - L007c: ret - L007d: mov rcx, rsi - L0080: call System.Threading.Tasks.Task.UpdateExceptionObservedStatus() - L0085: mov rcx, rdi - L0088: call 0x - L008d: int3 - -C.Foo(Int32) - L0000: sub rsp, 0x38 - L0004: xor eax, eax - L0006: mov [rsp+0x28], rax - L000b: mov [rsp+0x30], rax - L0010: xor eax, eax - L0012: mov [rsp+0x30], rax - L0017: mov [rsp+0x2c], ecx - L001b: mov dword ptr [rsp+0x28], 0x - L0023: lea rcx, [rsp+0x28] - L0028: call System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[C+d__1, _]](d__1 ByRef) - L002d: mov rax, [rsp+0x30] - L0032: test rax, rax - L0035: je short L003c - L0037: add rsp, 0x38 - L003b: ret - L003c: lea rcx, [rsp+0x30] - L0041: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, System.Private.CoreLib]].InitializeTaskAsPromise() - L0046: jmp short L0037 - -C+d__1.MoveNext() - L0000: push rbp - L0001: push rdi - L0002: push rsi - L0003: sub rsp, 0x30 - L0007: lea rbp, [rsp+0x40] - L000c: mov [rbp-0x20], rsp - L0010: mov [rbp+0x10], rcx - L0014: mov esi, [rcx+4] - L0017: mov dword ptr [rcx], 0x - L001d: lea rdi, [rcx+8] - L0021: cmp qword ptr [rdi], 0 - L0025: jne short L007a - L0027: mov eax, esi - L0029: inc eax - L002b: cmp eax, 0xa - L002e: jb short L0056 - L0030: mov rcx, 0x - L003a: call 0x - L003f: mov rdx, rax - L0042: mov dword ptr [rdx+0x34], 0x - L0049: mov [rdx+0x38], esi - L004c: mov rcx, rdi - L004f: call 0x - L0054: jmp short L0072 - L0056: mov rdx, 0x - L0060: mov rdx, [rdx] - L0063: cmp eax, [rdx+8] - L0066: jae short L0086 - L0068: movsxd rcx, eax - L006b: mov rdx, [rdx+rcx*8+0x10] - L0070: jmp short L004c - L0072: add rsp, 0x30 - L0076: pop rsi - L0077: pop rdi - L0078: pop rbp - L0079: ret - L007a: mov rcx, [rdi] - L007d: mov edx, esi - L007f: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, System.Private.CoreLib]].SetExistingTaskResult(System.Threading.Tasks.Task`1, Int32) - L0084: jmp short L0072 - L0086: call 0x - L008b: int3 - L008c: push rbp - L008d: push rdi - L008e: push rsi - L008f: sub rsp, 0x30 - L0093: mov rbp, [rcx+0x20] - L0097: mov [rsp+0x20], rbp - L009c: lea rbp, [rbp+0x40] - L00a0: mov rcx, [rbp+0x10] - L00a4: mov dword ptr [rcx], 0x - L00aa: add rcx, 8 - L00ae: call System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, System.Private.CoreLib]].SetException(System.Exception) - L00b3: lea rax, [L0072] - L00ba: add rsp, 0x30 - L00be: pop rsi - L00bf: pop rdi - L00c0: pop rbp - L00c1: ret - -C+d__1.SetStateMachine(System.Runtime.CompilerServices.IAsyncStateMachine) - L0000: sub rsp, 0x28 - L0004: add rcx, 8 - L0008: mov rcx, [rcx] - L000b: test rdx, rdx - L000e: je short L001a - L0010: test rcx, rcx - L0013: jne short L0025 - L0015: add rsp, 0x28 - L0019: ret - L001a: mov ecx, 0x3d - L001f: call System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument) - L0024: int3 - L0025: mov ecx, 0x25 - L002a: call System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource) - L002f: int3 \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs similarity index 60% rename from source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs index 27cb20f2c..e3ff0b789 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/ConsoleWrite.cs @@ -3,11 +3,13 @@ static class C { static void M() => Console.WriteLine("test"); } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C.M() L0000: mov rcx, 0x L000a: mov rcx, [rcx] - L000d: jmp System.Console.WriteLine(System.String) \ No newline at end of file + L000d: jmp qword ptr [0x] + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs similarity index 64% rename from source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs index f3edfb147..48a9b7d1f 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Delegate.cs @@ -1,17 +1,19 @@ delegate void D(); -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 -D..ctor(System.Object, IntPtr) +D..ctor(...) ; Cannot produce JIT assembly for runtime-implemented method. D.Invoke() ; Cannot produce JIT assembly for runtime-implemented method. -D.BeginInvoke(System.AsyncCallback, System.Object) +D.BeginInvoke(...) ; Cannot produce JIT assembly for runtime-implemented method. -D.EndInvoke(System.IAsyncResult) - ; Cannot produce JIT assembly for runtime-implemented method. \ No newline at end of file +D.EndInvoke(...) + ; Cannot produce JIT assembly for runtime-implemented method. + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/DllImport.cs b/source/Tests/Decompilation/TestCode/JitAsm/DllImport.cs index ead34ca46..583b78041 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/DllImport.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/DllImport.cs @@ -8,7 +8,7 @@ public static class NativeMethods /* asm -; Core CLR on amd64 +; Core CLR on x64 NativeMethods.GetLastError() ; Cannot produce JIT assembly for a P/Invoke method. diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs b/source/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs index 3a3b12545..8ee493ecb 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.ClassWithAttribute.cs @@ -11,22 +11,20 @@ static T M() { /* asm -; Core CLR on amd64 +; Core CLR on x64 C`1[[System.Int32, System.Private.CoreLib]].M() L0000: xor eax, eax L0002: ret C`1[[System.Decimal, System.Private.CoreLib]].M() - L0000: xor eax, eax - L0002: mov [rcx], eax - L0004: mov [rcx+4], eax - L0007: mov [rcx+8], rax - L000b: mov rax, rcx - L000e: ret + L0000: vxorps xmm0, xmm0, xmm0 + L0004: vmovdqu [rcx], xmm0 + L0008: mov rax, rcx + L000b: ret -C`1[[System.__Canon, System.Private.CoreLib]].M() - L0000: xor eax, eax - L0002: ret +C`1[[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].M() + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs similarity index 50% rename from source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs index d93c7e89c..5fc692ce1 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.MethodWithAttribute.cs @@ -8,22 +8,22 @@ static T M() { } } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C.M[[System.Int32, System.Private.CoreLib]]() L0000: xor eax, eax L0002: ret C.M[[System.Decimal, System.Private.CoreLib]]() - L0000: xor eax, eax - L0002: mov [rcx], eax - L0004: mov [rcx+4], eax - L0007: mov [rcx+8], rax - L000b: mov rax, rcx - L000e: ret + L0000: vxorps xmm0, xmm0, xmm0 + L0004: vmovdqu [rcx], xmm0 + L0008: mov rax, rcx + L000b: ret C.M[[System.String, System.Private.CoreLib]]() - ; Failed to find JIT output for generic method (reference types?). - ; If you know a solution, please comment at https://github.com/ashmind/SharpLab/issues/99. \ No newline at end of file + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs index 71cbf1c5a..87366a521 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnBoth.cs @@ -12,22 +12,22 @@ static class N { /* asm -; Core CLR on amd64 +; Core CLR on x64 C`1+N`1[[System.Int32, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]].M(Int32) L0000: xor eax, eax L0002: ret -C`1+N`1[[System.Int32, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].M(System.__Canon) - L0000: xor eax, eax - L0002: ret +C`1+N`1[[System.Int32, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].M(...) + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. -C`1+N`1[[System.__Canon, System.Private.CoreLib],[System.Int32, System.Private.CoreLib]].M(Int32) - L0000: xor eax, eax - L0002: ret +C`1+N`1[[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.Int32, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].M(...) + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. -C`1+N`1[[System.__Canon, System.Private.CoreLib],[System.__Canon, System.Private.CoreLib]].M(System.__Canon) - L0000: xor eax, eax - L0002: ret +C`1+N`1[[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].M(...) + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs index fe1310315..5e3ffc312 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnNested.cs @@ -10,14 +10,14 @@ static class N { /* asm -; Core CLR on amd64 +; Core CLR on x64 C+N`1[[System.Int32, System.Private.CoreLib]].get_M() L0000: xor eax, eax L0002: ret -C+N`1[[System.__Canon, System.Private.CoreLib]].get_M() - L0000: xor eax, eax - L0002: ret +C+N`1[[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].get_M() + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs index af5ad5a2a..91cc04df2 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Nested.AttributeOnTop.cs @@ -10,14 +10,14 @@ static class N { /* asm -; Core CLR on amd64 +; Core CLR on x64 C`1+N[[System.Int32, System.Private.CoreLib]].M() L0000: xor eax, eax L0002: ret -C`1+N[[System.__Canon, System.Private.CoreLib]].M() - L0000: xor eax, eax - L0002: ret +C`1+N[[System.String, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].M() + ; Failed to find JIT output. This might appear more frequently than before due to a library update. + ; Please monitor https://github.com/ashmind/SharpLab/issues/1334 for progress. */ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs similarity index 90% rename from source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs index 3d1a355ca..6c00565f5 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Generic.Open.Multiple.cs @@ -16,9 +16,9 @@ static void M() {} } } -#=> +/* asm -; Desktop CLR on x86 +; Core CLR on x64 C`1.M() ; Open generics cannot be JIT-compiled. @@ -30,7 +30,7 @@ static void M() {} ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. -C.M() +C.M[[, _]]() ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. @@ -38,4 +38,6 @@ static void M() {} C+N`1.M() ; Open generics cannot be JIT-compiled. ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types. - ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. \ No newline at end of file + ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M() { ... }. + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs similarity index 79% rename from source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs index 941f304ab..27f5b3ef7 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/JumpBack.cs @@ -10,9 +10,9 @@ public int M(int a) { } } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C..ctor() L0000: ret @@ -21,4 +21,6 @@ public int M(int a) { L0000: inc edx L0002: je short L0000 L0004: mov eax, edx - L0006: ret \ No newline at end of file + L0006: ret + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.NoFma.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.NoFma.cs2asm deleted file mode 100644 index dec6211fd..000000000 --- a/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.NoFma.cs2asm +++ /dev/null @@ -1,15 +0,0 @@ -// https://github.com/ashmind/SharpLab/issues/458 -using System; -public static class C { - public static double M(double a, double b, double c) { - return Math.FusedMultiplyAdd(a, b, c); - } -} - -#=> - -; Core CLR on amd64 - -C.M(Double, Double, Double) - L0000: vzeroupper - L0003: jmp System.Math.FusedMultiplyAdd(Double, Double, Double) \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.Fma.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs similarity index 65% rename from source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.Fma.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs index 66ad75a8d..6949f1667 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.Fma.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Math.FusedMultiplyAdd.cs @@ -6,11 +6,12 @@ public static double M(double a, double b, double c) { } } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C.M(Double, Double, Double) - L0000: vzeroupper - L0003: vfmadd213sd xmm0, xmm1, xmm2 - L0008: ret \ No newline at end of file + L0000: vfmadd213sd xmm0, xmm1, xmm2 + L0005: ret + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs b/source/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs new file mode 100644 index 000000000..56eab67bb --- /dev/null +++ b/source/Tests/Decompilation/TestCode/JitAsm/MethodImpl.InternalCall.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; + +public static class C { + [MethodImpl(MethodImplOptions.InternalCall)] + public static extern void M(); +} + +/* asm + +; Core CLR on x64 + +C.M() + ; Cannot produce JIT assembly for an internal call method. + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs b/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs new file mode 100644 index 000000000..8c80099d6 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs @@ -0,0 +1,18 @@ +static class C { + static int M(bool x) { + return x ? 1 : 2; + } +} + +/* asm + +; Core CLR on x64 + +C.M(Boolean) + L0000: mov eax, 1 + L0005: mov edx, 2 + L000a: test cl, cl + L000c: cmove eax, edx + L000f: ret + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm deleted file mode 100644 index 05eeb6d9b..000000000 --- a/source/Tests/Decompilation/TestCode/JitAsm/MultipleReturns.cs2asm +++ /dev/null @@ -1,17 +0,0 @@ -static class C { - static int M(bool x) { - return x ? 1 : 2; - } -} - -#=> - -; Core CLR on amd64 - -C.M(Boolean) - L0000: test cl, cl - L0002: jne short L000a - L0004: mov eax, 2 - L0009: ret - L000a: mov eax, 1 - L000f: ret \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs similarity index 64% rename from source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs index 27a15f818..8a58daabc 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Nested.Simple.cs @@ -4,10 +4,12 @@ static class N { } } -#=> +/* asm -; Core CLR on amd64 +; Core CLR on x64 C+N.M() L0000: mov eax, 0x12345 - L0005: ret \ No newline at end of file + L0005: ret + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Simple.cs similarity index 57% rename from source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm rename to source/Tests/Decompilation/TestCode/JitAsm/Simple.cs index b902cb71f..9a1246376 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm +++ b/source/Tests/Decompilation/TestCode/JitAsm/Simple.cs @@ -2,10 +2,12 @@ static class C { static int M() => 0x12345; } -#=> +/* asm -; Desktop CLR on x86 +; Core CLR on x64 C.M() L0000: mov eax, 0x12345 - L0005: ret \ No newline at end of file + L0005: ret + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm b/source/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm deleted file mode 100644 index d32ccd252..000000000 --- a/source/Tests/Decompilation/TestCode/JitAsm/Simple.cs2asm +++ /dev/null @@ -1,11 +0,0 @@ -static class C { - static int M() => 0x12345; -} - -#=> - -; Core CLR on amd64 - -C.M() - L0000: mov eax, 0x12345 - L0005: ret \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs b/source/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs index 08c35daf0..c272e56b7 100644 --- a/source/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs +++ b/source/Tests/Decompilation/TestCode/JitAsm/Vectors.Avx2.cs @@ -12,19 +12,18 @@ public int M(Vector256 vector) { /* asm -; Core CLR on amd64 +; Core CLR on x64 C..ctor() L0000: ret C.M(System.Runtime.Intrinsics.Vector256`1) - L0000: vzeroupper - L0003: vmovupd ymm0, [rdx] - L0007: vextracti128 xmm0, ymm0, 1 - L000d: vmovdqu ymm1, [rdx] - L0011: vpaddd xmm0, xmm1, xmm0 - L0015: vmovd eax, xmm0 - L0019: vzeroupper - L001c: ret + L0000: vmovups ymm0, [rdx] + L0004: vmovaps ymm1, ymm0 + L0008: vextracti128 xmm0, ymm0, 1 + L000e: vpaddd xmm0, xmm0, xmm1 + L0012: vmovd eax, xmm0 + L0016: vzeroupper + L0019: ret */ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs b/source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs similarity index 91% rename from source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs rename to source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs index 8ad7170e7..dac584c9e 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Lambda.CallInArray.cs2cs +++ b/source/Tests/Decompilation/TestCode/Lambda.CallInArray.cs @@ -7,7 +7,7 @@ public void M() { } } -#=> +/* cs using System; using System.Diagnostics; @@ -23,6 +23,8 @@ public void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { [Serializable] @@ -48,13 +50,16 @@ public void M() Console.WriteLine(array[3]); } } + [CompilerGenerated] internal sealed class { [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 16)] - private struct __StaticArrayInitTypeSize=16 + internal struct __StaticArrayInitTypeSize=16 { } internal static readonly __StaticArrayInitTypeSize=16 81C1A5A2F482E82CA2C66653482AB24E6D90944BF183C8164E8F8F8D72DB60DB/* Not supported: data(01 00 00 00 02 00 00 00 03 00 00 00 00 00 00 00) */; -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Lock.Simple.cs2cs b/source/Tests/Decompilation/TestCode/Lock.Simple.cs similarity index 89% rename from source/Tests/Decompilation/TestCode/Lock.Simple.cs2cs rename to source/Tests/Decompilation/TestCode/Lock.Simple.cs index 0520462a7..d5715250d 100644 --- a/source/Tests/Decompilation/TestCode/Lock.Simple.cs2cs +++ b/source/Tests/Decompilation/TestCode/Lock.Simple.cs @@ -9,7 +9,7 @@ public void M(object o) { } } -#=> +/* cs using System; using System.Diagnostics; @@ -25,8 +25,11 @@ public void M(object o) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { + [NullableContext(1)] public void M(object o) { bool lockTaken = false; @@ -43,4 +46,6 @@ public void M(object o) } } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Module.vb2cs b/source/Tests/Decompilation/TestCode/Module.vb similarity index 93% rename from source/Tests/Decompilation/TestCode/Module.vb2cs rename to source/Tests/Decompilation/TestCode/Module.vb index 678ecd82d..326343dff 100644 --- a/source/Tests/Decompilation/TestCode/Module.vb2cs +++ b/source/Tests/Decompilation/TestCode/Module.vb @@ -1,7 +1,7 @@ Public Module M End Module -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -12,7 +12,10 @@ using Microsoft.VisualBasic.CompilerServices; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] + [StandardModule] public sealed class M { -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs b/source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs similarity index 90% rename from source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs rename to source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs index ef17abae5..078d4c1d3 100644 --- a/source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs2cs +++ b/source/Tests/Decompilation/TestCode/NullPropagation.ToTernary.cs @@ -5,7 +5,7 @@ public int M(Point p) { } } -#=> +/* cs using System; using System.Diagnostics; @@ -20,6 +20,8 @@ public int M(Point p) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class Point { [CompilerGenerated] @@ -39,9 +41,12 @@ public int X } } + [NullableContext(1)] public int M(Point p) { Nullable num = ((p != null) ? new Nullable(p.X) : null); return num.GetValueOrDefault(); } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs b/source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs similarity index 91% rename from source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs rename to source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs index 9dddcbc5d..9244c5d3d 100644 --- a/source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs2cs +++ b/source/Tests/Decompilation/TestCode/Nullable.OperatorLifting.cs @@ -5,7 +5,7 @@ public bool M(DateTime? d) { } } -#=> +/* cs using System; using System.Diagnostics; @@ -20,6 +20,8 @@ public bool M(DateTime? d) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { public bool M(Nullable d) @@ -32,4 +34,6 @@ public bool M(Nullable d) } return dateTime.GetValueOrDefault() > now; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Nullable.Reference.Simple.IL.cs b/source/Tests/Decompilation/TestCode/Nullable.Reference.Simple.IL.cs new file mode 100644 index 000000000..5db228499 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/Nullable.Reference.Simple.IL.cs @@ -0,0 +1,92 @@ +void M(object? value) { +} + +/* il + +.assembly _ +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( + 01 00 08 00 00 00 00 00 + ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( + 01 00 01 00 54 02 16 57 72 61 70 4e 6f 6e 45 78 + 63 65 70 74 69 6f 6e 54 68 72 6f 77 73 01 + ) + .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( + 01 00 02 00 00 00 00 00 + ) + .permissionset reqmin = ( + 2e 01 80 8a 53 79 73 74 65 6d 2e 53 65 63 75 72 + 69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e + 53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69 + 6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73 + 74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72 + 73 69 6f 6e 3d 39 2e 30 2e 30 2e 30 2c 20 43 75 + 6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50 + 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30 + 33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01 + 54 02 10 53 6b 69 70 56 65 72 69 66 69 63 61 74 + 69 6f 6e 01 + ) + .hash algorithm 0x // SHA1 + .ver 0:0:0:0 +} + +.class private auto ansi '' +{ +} // end of class + +.class private auto ansi beforefieldinit Program + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method private hidebysig static + void '
$' ( + string[] args + ) cil managed + { + // Method begins at RVA 0x2050 + // Code size 1 (0x1) + .maxstack 8 + .entrypoint + + IL_0000: ret + } // end of method Program::'
$' + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + // Method begins at RVA 0x2052 + // Code size 7 (0x7) + .maxstack 8 + + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: ret + } // end of method Program::.ctor + + .method assembly hidebysig static + void '<
$>g__M|0_0' ( + object 'value' + ) cil managed + { + .custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( + 01 00 02 00 00 + ) + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Method begins at RVA 0x2050 + // Code size 1 (0x1) + .maxstack 8 + + // sequence point: (line 2, col 1) to (line 2, col 2) in _ + IL_0000: ret + } // end of method Program::'<
$>g__M|0_0' + +} // end of class Program + +*/ \ No newline at end of file diff --git a/source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs b/source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs similarity index 90% rename from source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs rename to source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs index 6255c2aef..378863359 100644 --- a/source/NetFramework/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs +++ b/source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs @@ -3,7 +3,7 @@ public void M(decimal d = 5.0m) { } } -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -18,9 +18,13 @@ public void M(decimal d = 5.0m) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { public void M([Optional][DecimalConstant(1, 0, 0u, 0u, 50u)] decimal d) { } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs b/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs index 49c80075f..b0d280301 100644 --- a/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs +++ b/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.cs @@ -23,8 +23,11 @@ public string M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { + [NullableContext(1)] public string M() { return "Debug"; diff --git a/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb2cs b/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb similarity index 94% rename from source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb2cs rename to source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb index c00462832..237f3e4d8 100644 --- a/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb2cs +++ b/source/Tests/Decompilation/TestCode/Preprocessor.IfDebug.vb @@ -8,7 +8,7 @@ Public Class C End Function End Class -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -18,10 +18,13 @@ using System.Runtime.CompilerServices; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue | DebuggableAttribute.DebuggingModes.DisableOptimizations)] [assembly: AssemblyVersion("0.0.0.0")] + public class C { public string M() { return "Debug"; } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Property.InitOnly.cs2cs b/source/Tests/Decompilation/TestCode/Property.InitOnly.cs similarity index 91% rename from source/Tests/Decompilation/TestCode/Property.InitOnly.cs2cs rename to source/Tests/Decompilation/TestCode/Property.InitOnly.cs index 7b34349e2..cd85b933e 100644 --- a/source/Tests/Decompilation/TestCode/Property.InitOnly.cs2cs +++ b/source/Tests/Decompilation/TestCode/Property.InitOnly.cs @@ -2,7 +2,7 @@ public class C { public int P { get; init; } } -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -16,6 +16,8 @@ public class C { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { [CompilerGenerated] @@ -34,4 +36,6 @@ public int P

k__BackingField = value; } } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs b/source/Tests/Decompilation/TestCode/Scopes.File.cs similarity index 68% rename from source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs rename to source/Tests/Decompilation/TestCode/Scopes.File.cs index 6255c2aef..cf9769630 100644 --- a/source/Tests/Decompilation/TestCode/Parameters.Optional.Decimal.cs2cs +++ b/source/Tests/Decompilation/TestCode/Scopes.File.cs @@ -1,14 +1,10 @@ -public class C { - public void M(decimal d = 5.0m) { - } -} +file class C {} -#=> +/* cs using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Security; using System.Security.Permissions; @@ -18,9 +14,10 @@ public void M(decimal d = 5.0m) { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] -public class C +[module: RefSafetyRules(11)] + +internal class <_>FD2E2ADF7177B7A8AFDDBC12D1634CF23EA1A71020F6A1308070A16400FB68FDE__C { - public void M([Optional][DecimalConstant(1, 0, 0u, 0u, 50u)] decimal d) - { - } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Simple.cs b/source/Tests/Decompilation/TestCode/Simple.cs index 421f827e5..dc4044d98 100644 --- a/source/Tests/Decompilation/TestCode/Simple.cs +++ b/source/Tests/Decompilation/TestCode/Simple.cs @@ -3,7 +3,7 @@ public class Simple { /* il - .assembly _ +.assembly _ { .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 @@ -21,7 +21,7 @@ 69 74 79 2e 50 65 72 6d 69 73 73 69 6f 6e 73 2e 53 65 63 75 72 69 74 79 50 65 72 6d 69 73 73 69 6f 6e 41 74 74 72 69 62 75 74 65 2c 20 53 79 73 74 65 6d 2e 52 75 6e 74 69 6d 65 2c 20 56 65 72 - 73 69 6f 6e 3d 36 2e 30 2e 30 2e 30 2c 20 43 75 + 73 69 6f 6e 3d 39 2e 30 2e 30 2e 30 2c 20 43 75 6c 74 75 72 65 3d 6e 65 75 74 72 61 6c 2c 20 50 75 62 6c 69 63 4b 65 79 54 6f 6b 65 6e 3d 62 30 33 66 35 66 37 66 31 31 64 35 30 61 33 61 15 01 diff --git a/source/Tests/Decompilation/TestCode/Simple.vb2cs b/source/Tests/Decompilation/TestCode/Simple.vb similarity index 92% rename from source/Tests/Decompilation/TestCode/Simple.vb2cs rename to source/Tests/Decompilation/TestCode/Simple.vb index 0981cd4cd..15bee169f 100644 --- a/source/Tests/Decompilation/TestCode/Simple.vb2cs +++ b/source/Tests/Decompilation/TestCode/Simple.vb @@ -3,7 +3,7 @@ Public Class C End Sub End Class -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -13,9 +13,12 @@ using System.Runtime.CompilerServices; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] + public class C { public void M() { } -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs b/source/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs index 22b5433e1..e6f6c87a4 100644 --- a/source/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs +++ b/source/Tests/Decompilation/TestCode/StringInterpolation.Simple.cs @@ -21,11 +21,17 @@ public void M() [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { public void M() { - string text = string.Format("This {0} That", 1); + DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(10, 1); + defaultInterpolatedStringHandler.AppendLiteral("This "); + defaultInterpolatedStringHandler.AppendFormatted(1); + defaultInterpolatedStringHandler.AppendLiteral(" That"); + string text = defaultInterpolatedStringHandler.ToStringAndClear(); string text2 = string.Concat("This ", text, " That"); } } diff --git a/source/Tests/Decompilation/TestCode/Switch.String.Large.cs b/source/Tests/Decompilation/TestCode/Switch.String.Large.cs new file mode 100644 index 000000000..8798109c6 --- /dev/null +++ b/source/Tests/Decompilation/TestCode/Switch.String.Large.cs @@ -0,0 +1,97 @@ +// https://github.com/ashmind/SharpLab/issues/489 +public class C +{ + public string M(string key) + { + switch (key) + { + case "Key1": return "1"; + case "Key2": return "2"; + case "Key3": return "3"; + case "Key4": return "4"; + case "Key5": return "5"; + case "Key6": return "6"; + case "Key7": return "7"; + default: return "?"; + } + } +} + +/* cs + +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security; +using System.Security.Permissions; + +[assembly: CompilationRelaxations(8)] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] +[assembly: AssemblyVersion("0.0.0.0")] +[module: UnverifiableCode] +[module: RefSafetyRules(11)] + +public class C +{ + [NullableContext(1)] + public string M(string key) + { + if (key != null) + { + int length = key.Length; + if (length == 4) + { + switch (key[3]) + { + case '1': + if (!(key == "Key1")) + { + break; + } + return "1"; + case '2': + if (!(key == "Key2")) + { + break; + } + return "2"; + case '3': + if (!(key == "Key3")) + { + break; + } + return "3"; + case '4': + if (!(key == "Key4")) + { + break; + } + return "4"; + case '5': + if (!(key == "Key5")) + { + break; + } + return "5"; + case '6': + if (!(key == "Key6")) + { + break; + } + return "6"; + case '7': + if (!(key == "Key7")) + { + break; + } + return "7"; + } + } + } + return "?"; + } +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Switch.String.Large.cs2cs b/source/Tests/Decompilation/TestCode/Switch.String.Large.cs2cs deleted file mode 100644 index 50f829450..000000000 --- a/source/Tests/Decompilation/TestCode/Switch.String.Large.cs2cs +++ /dev/null @@ -1,106 +0,0 @@ -// https://github.com/ashmind/SharpLab/issues/489 -public class C -{ - public string M(string key) - { - switch (key) - { - case "Key1": return "1"; - case "Key2": return "2"; - case "Key3": return "3"; - case "Key4": return "4"; - case "Key5": return "5"; - case "Key6": return "6"; - case "Key7": return "7"; - default: return "?"; - } - } -} - -#=> - -using System.Diagnostics; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Security; -using System.Security.Permissions; - -[assembly: CompilationRelaxations(8)] -[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] -[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] -[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] -[assembly: AssemblyVersion("0.0.0.0")] -[module: UnverifiableCode] -public class C -{ - public string M(string key) - { - uint num = .ComputeStringHash(key); - if (num <= 455788110) - { - if (num != 422232872) - { - if (num != 439010491) - { - if (num == 455788110 && key == "Key6") - { - return "6"; - } - } - else if (key == "Key5") - { - return "5"; - } - } - else if (key == "Key4") - { - return "4"; - } - } - else if (num <= 506120967) - { - if (num != 472565729) - { - if (num == 506120967 && key == "Key1") - { - return "1"; - } - } - else if (key == "Key7") - { - return "7"; - } - } - else if (num != 522898586) - { - if (num == 539676205 && key == "Key3") - { - return "3"; - } - } - else if (key == "Key2") - { - return "2"; - } - return "?"; - } -} -[CompilerGenerated] -internal sealed class -{ - internal static uint ComputeStringHash(string s) - { - uint num = default(uint); - if (s != null) - { - num = 2166136261u; - int num2 = 0; - while (num2 < s.Length) - { - num = (s[num2] ^ num) * 16777619; - num2++; - } - } - return num; - } -} \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs b/source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs similarity index 92% rename from source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs rename to source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs index a53197774..1511d4159 100644 --- a/source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs2cs +++ b/source/Tests/Decompilation/TestCode/Unsafe.FixedBuffer.cs @@ -3,7 +3,7 @@ internal unsafe struct MyBuffer public fixed char fixedBuffer[128]; } -#=> +/* cs using System.Diagnostics; using System.Reflection; @@ -18,6 +18,8 @@ internal unsafe struct MyBuffer [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + internal struct MyBuffer { [StructLayout(LayoutKind.Sequential, Size = 256)] @@ -30,4 +32,6 @@ public struct e__FixedBuffer [FixedBuffer(typeof(char), 128)] public e__FixedBuffer fixedBuffer; -} \ No newline at end of file +} + +*/ \ No newline at end of file diff --git a/source/Tests/Decompilation/TestCode/Using.Simple.cs b/source/Tests/Decompilation/TestCode/Using.Simple.cs index abeb6279b..2c35ab77d 100644 --- a/source/Tests/Decompilation/TestCode/Using.Simple.cs +++ b/source/Tests/Decompilation/TestCode/Using.Simple.cs @@ -21,6 +21,8 @@ public void M() { [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] +[module: RefSafetyRules(11)] + public class C { public void M() diff --git a/source/Tests/Execution/CompilationTests.cs b/source/Tests/Execution/CompilationTests.cs deleted file mode 100644 index d5af75489..000000000 --- a/source/Tests/Execution/CompilationTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Threading.Tasks; -using SharpLab.Tests.Execution.Internal; -using SharpLab.Tests.Internal; -using Xunit; - -namespace SharpLab.Tests.Execution { - [Collection(TestCollectionNames.Execution)] - public class CompilationTests { - [Theory] - [InlineData("UnsafeKeyword.cs")] - public async Task Compilation_IsIncludedInOutput(string codeFileName) { - // Arrange - var code = await TestCode.FromCodeOnlyFileAsync("Compilation/" + codeFileName); - - // Act - var output = await ContainerTestDriver.CompileAndExecuteAsync(code); - - // Assert - Assert.DoesNotMatch("Exception:", output); - } - } -} diff --git a/source/Tests/Execution/ExceptionTests.cs b/source/Tests/Execution/ExceptionTests.cs index f4238553d..b2da80be8 100644 --- a/source/Tests/Execution/ExceptionTests.cs +++ b/source/Tests/Execution/ExceptionTests.cs @@ -8,10 +8,11 @@ namespace SharpLab.Tests.Execution { [Collection(TestCollectionNames.Execution)] public class ExceptionTests { - private readonly ITestOutputHelper _testOutputHelper; + private readonly ITestOutputHelper _outputHelper; - public ExceptionTests(ITestOutputHelper testOutputHelper) { - _testOutputHelper = testOutputHelper; + public ExceptionTests(ITestOutputHelper outputHelper) { + _outputHelper = outputHelper; + // TestDiagnosticLog.Enable(outputHelper); } [Theory] @@ -34,7 +35,7 @@ public async Task Exceptions_AreReportedInFlow( var output = await ContainerTestDriver.CompileAndExecuteAsync(code, optimizationLevel: optimizationLevel); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _outputHelper); } [Fact] diff --git a/source/Tests/Execution/FSharpTests.cs b/source/Tests/Execution/FSharpTests.cs index 971e11288..d7169e8f5 100644 --- a/source/Tests/Execution/FSharpTests.cs +++ b/source/Tests/Execution/FSharpTests.cs @@ -3,36 +3,57 @@ using Xunit; using SharpLab.Tests.Execution.Internal; using SharpLab.Tests.Internal; +using Xunit.Abstractions; -namespace SharpLab.Tests.Execution { - [Collection(TestCollectionNames.Execution)] - public class FSharpTests { - [Fact] - public async Task FSharp_Simple() { - var code = @" - open System - printf ""Test"" - "; +namespace SharpLab.Tests.Execution; + +[Collection(TestCollectionNames.Execution)] +public class FSharpTests { + public FSharpTests(ITestOutputHelper output) { + // TestDiagnosticLog.Enable(output); + } + + [Fact] + public async Task FSharp_Simple() { + // Arrange + var code = @" + open System + printf ""Test"" + "; + + // Act + var output = await ContainerTestDriver.CompileAndExecuteAsync(code, LanguageNames.FSharp); - var output = await ContainerTestDriver.CompileAndExecuteAsync(code, LanguageNames.FSharp); + // Assert + Assert.Equal("Test", output); + } + + [Fact] + public async Task FSharp_WithExplicitEntryPoint() { + // Arrange + var code = @" + open System - Assert.Equal("Test", output); - } + [] + let main argv = + printf ""Test"" + 0 + "; - [Fact] - public async Task FSharp_WithExplicitEntryPoint() { - var code = @" - open System + // Act + var output = await ContainerTestDriver.CompileAndExecuteAsync(code, LanguageNames.FSharp); + + // Assert + Assert.Equal("Test", output); + } - [] - let main argv = - printf ""Test"" - 0 - "; - var output = await ContainerTestDriver.CompileAndExecuteAsync(code, LanguageNames.FSharp); + [Fact] + public async Task FSharp_Empty() { + // Act + var output = await ContainerTestDriver.CompileAndExecuteAsync("", LanguageNames.FSharp); - Assert.Equal("Test", output); - } + // Assert + Assert.Equal("", output); } } diff --git a/source/Tests/Execution/FlowJumpTests.cs b/source/Tests/Execution/FlowJumpTests.cs new file mode 100644 index 000000000..a4dc0bed7 --- /dev/null +++ b/source/Tests/Execution/FlowJumpTests.cs @@ -0,0 +1,29 @@ +using System.Threading.Tasks; +using SharpLab.Tests.Execution.Internal; +using SharpLab.Tests.Internal; +using Xunit; +using Xunit.Abstractions; + +namespace SharpLab.Tests.Execution { + [Collection(TestCollectionNames.Execution)] + public class FlowJumpTests { + private readonly ITestOutputHelper _testOutputHelper; + + public FlowJumpTests(ITestOutputHelper testOutputHelper) { + _testOutputHelper = testOutputHelper; + } + + [Theory] + [InlineData("Call.InternalAndExternal.cs")] + public async Task Flow_IncludesExpectedJumps(string codeFileName) { + // Arrange + var code = await TestCode.FromCodeOnlyFileAsync("Flow/Jumps/" + codeFileName); + + // Act + var output = await ContainerTestDriver.CompileAndExecuteAsync(code); + + // Assert + TestOutput.AssertFlowMatchesJumpComments(code, output, _testOutputHelper); + } + } +} diff --git a/source/Tests/Execution/FlowValueTests.cs b/source/Tests/Execution/FlowValueTests.cs index dbe5f2ca7..6ce8bb41e 100644 --- a/source/Tests/Execution/FlowValueTests.cs +++ b/source/Tests/Execution/FlowValueTests.cs @@ -3,6 +3,7 @@ using Xunit.Abstractions; using SharpLab.Tests.Execution.Internal; using SharpLab.Tests.Internal; +using System.Text.RegularExpressions; namespace SharpLab.Tests.Execution { [Collection(TestCollectionNames.Execution)] @@ -26,15 +27,18 @@ public FlowValueTests(ITestOutputHelper testOutputHelper) { [InlineData("Variable.LongValue.UnicodeCharBreak.cs")] [InlineData("Regression.ToStringNull.cs")] // https://github.com/ashmind/SharpLab/issues/380 [InlineData("Variable.Array.cs")] + [InlineData("Argument.Array.Generic.cs")] public async Task Flow_IncludesExpectedValues(string codeFileName) { // Arrange var code = await TestCode.FromCodeOnlyFileAsync("Flow/Values/" + codeFileName); + // required to avoid roslyn guards rejecting consecutive [] in comments + var codeWithoutComments = Regex.Replace(code, @"\s*//.*$", "", RegexOptions.Multiline); // Act - var output = await ContainerTestDriver.CompileAndExecuteAsync(code); + var output = await ContainerTestDriver.CompileAndExecuteAsync(codeWithoutComments); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _testOutputHelper); } [Theory] @@ -66,7 +70,7 @@ public static void Main() { " + methodCallCode + @" } var output = await ContainerTestDriver.CompileAndExecuteAsync(code); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _testOutputHelper); } [Fact] @@ -84,7 +88,7 @@ public void M(int a) {} // [a: 1] var output = await ContainerTestDriver.CompileAndExecuteAsync(code); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _testOutputHelper); } [Fact] @@ -102,7 +106,7 @@ public class Program { var output = await ContainerTestDriver.CompileAndExecuteAsync(code); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _testOutputHelper); } [Fact] @@ -118,7 +122,7 @@ public static class Program { var output = await ContainerTestDriver.CompileAndExecuteAsync(code); // Assert - TestOutput.AssertFlowMatchesComments(code, output, _testOutputHelper); + TestOutput.AssertFlowMatchesValueComments(code, output, _testOutputHelper); } } } diff --git a/source/Tests/Execution/InspectHeapTests.cs b/source/Tests/Execution/InspectHeapTests.cs index ba6f520b4..fad536177 100644 --- a/source/Tests/Execution/InspectHeapTests.cs +++ b/source/Tests/Execution/InspectHeapTests.cs @@ -14,17 +14,17 @@ public InspectHeapTests(ITestOutputHelper testOutputHelper) { } [Theory] - [InlineData("Simple.cs2output")] - [InlineData("Struct.cs2output")] - [InlineData("Struct.Nested.cs2output")] - [InlineData("Int32.cs2output")] - //[InlineData("Null.cs2output"/*, true*/)] + [InlineData("Simple.cs")] + [InlineData("Struct.cs")] + [InlineData("Struct.Nested.cs")] + [InlineData("Int32.cs")] + //[InlineData("Null.cs"/*, true*/)] public async Task InspectHeap_ProducesExpectedOutput(string resourceName/*, bool allowExceptions = false*/) { var code = await TestCode.FromFileAsync("Inspect/Heap/" + resourceName); var output = await ContainerTestDriver.CompileAndExecuteAsync(code.Original); - code.AssertIsExpected(TestOutput.RemoveFlowJson(output), _testOutputHelper); + await code.AssertIsExpectedAsync(TestOutput.RemoveFlowJson(output), _testOutputHelper); } } } diff --git a/source/Tests/Execution/InspectMemoryGraphTests.cs b/source/Tests/Execution/InspectMemoryGraphTests.cs index a659cf7dd..2d5d67ded 100644 --- a/source/Tests/Execution/InspectMemoryGraphTests.cs +++ b/source/Tests/Execution/InspectMemoryGraphTests.cs @@ -14,18 +14,18 @@ public InspectMemoryGraphTests(ITestOutputHelper testOutputHelper) { } [Theory] - [InlineData("Int32.cs2output")] - [InlineData("String.cs2output")] + [InlineData("Int32.cs")] + [InlineData("String.cs")] [InlineData("Arrays.cs")] - [InlineData("Variables.cs2output")] - [InlineData("DateTime.cs2output")] // https://github.com/ashmind/SharpLab/issues/379 - [InlineData("Null.cs2output")] + [InlineData("Variables.cs")] + [InlineData("DateTime.cs")] // https://github.com/ashmind/SharpLab/issues/379 + [InlineData("Null.cs")] public async Task InspectMemoryGraph_ProducesExpectedOutput(string resourceName) { var code = await TestCode.FromFileAsync("Inspect/MemoryGraph/" + resourceName); var output = await ContainerTestDriver.CompileAndExecuteAsync(code.Original); - code.AssertIsExpected(TestOutput.RemoveFlowJson(output), _testOutputHelper); + await code.AssertIsExpectedAsync(TestOutput.RemoveFlowJson(output), _testOutputHelper); } } } diff --git a/source/Tests/Execution/Internal/ContainerTestDriver.cs b/source/Tests/Execution/Internal/ContainerTestDriver.cs index 872cab1f9..1aef1e50f 100644 --- a/source/Tests/Execution/Internal/ContainerTestDriver.cs +++ b/source/Tests/Execution/Internal/ContainerTestDriver.cs @@ -21,92 +21,99 @@ using SharpLab.Tests.Internal; using LanguageNames = SharpLab.Server.Common.LanguageNames; -namespace SharpLab.Tests.Execution.Internal { - // TODO: Consolidate into standard SlowUpdate - public class ContainerTestDriver { - public static async Task CompileAndExecuteAsync(string code, string languageName = LanguageNames.CSharp, OptimizationLevel optimizationLevel = OptimizationLevel.Debug) { - var session = await PrepareWorkSessionAsync(code, languageName, optimizationLevel); +namespace SharpLab.Tests.Execution.Internal; - var assemblyStream = new MemoryStream(); - var symbolStream = new MemoryStream(); - var diagnostics = new List(); - var (compiled, hasSymbols) = await new Compiler(new RecyclableMemoryStreamManager()).TryCompileToStreamAsync( - assemblyStream, - symbolStream, - session, - diagnostics, - CancellationToken.None - ); - if (!compiled) - throw new Exception("Compilation failed:\n" + string.Join('\n', diagnostics)); - assemblyStream.Position = 0; - symbolStream.Position = 0; +// TODO: Consolidate into standard SlowUpdate +public class ContainerTestDriver { + public static async Task CompileAndExecuteAsync(string code, string languageName = LanguageNames.CSharp, OptimizationLevel optimizationLevel = OptimizationLevel.Debug) { + var session = await PrepareWorkSessionAsync(code, languageName, optimizationLevel); - var streams = new CompilationStreamPair(assemblyStream, hasSymbols ? symbolStream : null); - var executor = CreateContainerExecutor(); - return (await executor.ExecuteAsync(streams, session, CancellationToken.None)).Output; - } + var assemblyStream = new MemoryStream(); + var symbolStream = new MemoryStream(); + var diagnostics = new List(); + var (compiled, hasSymbols) = await new Compiler( + new RecyclableMemoryStreamManager() + ).TryCompileToStreamAsync( + assemblyStream, + symbolStream, + session, + diagnostics, + CancellationToken.None + ); + if (!compiled) + throw new Exception("Compilation failed:\n" + string.Join('\n', diagnostics)); + assemblyStream.Position = 0; + symbolStream.Position = 0; - private static async Task PrepareWorkSessionAsync(string code, string languageName, OptimizationLevel optimizationLevel) { - var mirrorsharp = await TestDriverFactory.FromCodeAsync( - code, languageName, TargetNames.Run, - optimize: optimizationLevel == OptimizationLevel.Release ? Optimize.Release : Optimize.Debug - ); - // forces mock to exist - TestEnvironment.Container.Resolve(); - await mirrorsharp.SendSlowUpdateAsync(); + var streams = new CompilationStreamPair(assemblyStream, hasSymbols ? symbolStream : null); + var executor = CreateContainerExecutor(); + return (await executor.ExecuteAsync(streams, session, CancellationToken.None)).Output; + } - return mirrorsharp.Session; - } + private static async Task PrepareWorkSessionAsync(string code, string languageName, OptimizationLevel optimizationLevel) { + var mirrorsharp = await TestDriverFactory.FromCodeAsync( + code, languageName, TargetNames.Run, + optimize: optimizationLevel == OptimizationLevel.Release ? Optimize.Release : Optimize.Debug + ); + // forces mock to exist + TestEnvironment.Container.Resolve(); + await mirrorsharp.SendSlowUpdateAsync(); - private static IContainerExecutor CreateContainerExecutor() { - using var containerScope = TestEnvironment.Container.BeginLifetimeScope(builder => { - builder.RegisterType().As(); + return mirrorsharp.Session; + } - // Override as transient - builder.RegisterType() - .As() - .InstancePerDependency(); - }); - return containerScope.Resolve(); - } + private static IContainerExecutor CreateContainerExecutor() { + using var containerScope = TestEnvironment.Container.BeginLifetimeScope(builder => { + builder.RegisterType().As(); - private class TestContainerClient : IContainerClient { - public async Task ExecuteAsync(string sessionId, Stream assemblyStream, bool includePerformance, CancellationToken cancellationToken) { - var startMarker = Guid.NewGuid(); - var endMarker = Guid.NewGuid(); - var executeCommand = new ExecuteCommand( - ((MemoryStream)assemblyStream).ToArray(), - startMarker, endMarker, - includePerformance - ); + // Override as transient + builder.RegisterType() + .As() + .InstancePerDependency(); + }); + return containerScope.Resolve(); + } + + private class TestContainerClient : IContainerClient { + public async Task ExecuteAsync(string sessionId, Stream assemblyStream, bool includePerformance, CancellationToken cancellationToken) { + var startMarker = Guid.NewGuid(); + var endMarker = Guid.NewGuid(); - var stdin = new MemoryStream(); - Serializer.SerializeWithLengthPrefix(stdin, executeCommand, PrefixStyle.Base128); - stdin.Seek(0, SeekOrigin.Begin); + var assemblyBytes = ((MemoryStream)assemblyStream).ToArray(); + if (assemblyStream.Position > 0) + assemblyBytes = assemblyBytes.AsSpan().Slice((int)assemblyStream.Position).ToArray(); - var stdout = new MemoryStream(); - var savedConsoleOut = Console.Out; - Console.SetOut(new StreamWriter(stdout) { AutoFlush = true }); - try { - Program.Run(stdin, stdout, () => {}); - } - finally { - Console.SetOut(savedConsoleOut); - } + var executeCommand = new ExecuteCommand( + assemblyBytes, + startMarker, endMarker, + includePerformance + ); - stdout.Seek(0, SeekOrigin.Begin); - var stdoutReader = new StdoutReader(new LoggerMock()); - var outputResult = await stdoutReader.ReadOutputAsync( - stdout, - new byte[stdout.Length], - Encoding.UTF8.GetBytes(startMarker.ToString()), - Encoding.UTF8.GetBytes(endMarker.ToString()), - cancellationToken - ); + var stdin = new MemoryStream(); + Serializer.SerializeWithLengthPrefix(stdin, executeCommand, PrefixStyle.Base128); + stdin.Seek(0, SeekOrigin.Begin); - return new(Encoding.UTF8.GetString(outputResult.Output.Span), outputFailed: false); + var stdout = new MemoryStream(); + var savedConsoleOut = Console.Out; + Console.SetOut(new StreamWriter(stdout) { AutoFlush = true }); + try { + Program.Run(stdin, stdout, () => {}); + } + finally { + Console.SetOut(savedConsoleOut); } + + stdout.Seek(0, SeekOrigin.Begin); + var stdoutReader = new StdoutReader(new LoggerMock()); + var outputResult = await stdoutReader.ReadOutputAsync( + stdout, + new byte[stdout.Length], + Encoding.UTF8.GetBytes(startMarker.ToString()), + Encoding.UTF8.GetBytes(endMarker.ToString()), + cancellationToken + ); + + return new(Encoding.UTF8.GetString(outputResult.Output.Span), outputFailed: false); } } } diff --git a/source/Tests/Execution/Internal/TestOutput.cs b/source/Tests/Execution/Internal/TestOutput.cs index 19cbdcb08..5f41baf8e 100644 --- a/source/Tests/Execution/Internal/TestOutput.cs +++ b/source/Tests/Execution/Internal/TestOutput.cs @@ -11,50 +11,87 @@ public static string RemoveFlowJson(string output) { return Regex.Replace(output, "#\\{\"flow\".+$", "", RegexOptions.Singleline); } - public static void AssertFlowMatchesComments(string code, string output, ITestOutputHelper testOutputHelper) { - var actual = ApplyActualFlowAsComments(code, output); + public static void AssertFlowMatchesValueComments(string code, string output, ITestOutputHelper testOutputHelper) { + AssertFlowMatchesComments(code, output, AssertCommentMode.Values, testOutputHelper); + } + + public static void AssertFlowMatchesJumpComments(string code, string output, ITestOutputHelper testOutputHelper) { + AssertFlowMatchesComments(code, output, AssertCommentMode.Jumps, testOutputHelper); + } + + private static void AssertFlowMatchesComments(string code, string output, AssertCommentMode mode, ITestOutputHelper testOutputHelper) { + var actual = ApplyActualFlowAsComments(code, output, mode); testOutputHelper.WriteLine(actual); Assert.Equal(code, actual); } - private static string ApplyActualFlowAsComments(string code, string output) { + private static string ApplyActualFlowAsComments(string code, string output, AssertCommentMode mode) { var cleanCodeLines = code.Split("\r\n") .Select(line => Regex.Replace(line, @"//.+$", "")); - var valuesByLineNumber = ExtractAndGroupFlowValueStepsByLineNumber(output); + var notesByLineNumber = ExtractAndGroupFlowNotesForComments(output, mode); return string.Join("\r\n", cleanCodeLines.Select( - (line, index) => line + (valuesByLineNumber.TryGetValue(index + 1, out var values) ? $"// [{values}]" : "") + (line, index) => line + (notesByLineNumber.TryGetValue(index + 1, out var note) ? $"// {note}" : "") )); } - private static IReadOnlyDictionary ExtractAndGroupFlowValueStepsByLineNumber(string output) { - var valuesByLineNumber = new Dictionary>>(); - IList> GetOrAddValues(int lineNumber) { - if (!valuesByLineNumber!.TryGetValue(lineNumber, out var values)) { - values = new List>(); - valuesByLineNumber.Add(lineNumber, values); + private static IReadOnlyDictionary ExtractAndGroupFlowNotesForComments(string output, AssertCommentMode mode) { + var groupsByLineNumber = new Dictionary>(); + IList GetOrAddNoteGroups(int lineNumber) { + if (!groupsByLineNumber!.TryGetValue(lineNumber, out var groups)) { + groups = new List { new LineNoteGroup() }; + groupsByLineNumber.Add(lineNumber, groups); } - return values; + return groups; } - + + var lastLineNumber = (int?)null; foreach (var step in ExtractFlowSteps(output)) { - if (step.Value == null) { // non-value step - GetOrAddValues(step.LineNumber).Add(new List()); - continue; - } + switch (step) { + case LineStep l: + lastLineNumber = l.LineNumber; + GetOrAddNoteGroups(l.LineNumber).Add(new()); + break; + + case ValueStep v when mode == AssertCommentMode.Values: { + lastLineNumber = v.LineNumber; + var notesLists = GetOrAddNoteGroups(v.LineNumber); + GetOrAddNoteGroups(v.LineNumber).Last() + .Values.Add(v.Name != null ? $"{v.Name}: {v.Value}" : v.Value); + break; + } + + case JumpStep j when mode == AssertCommentMode.Jumps && lastLineNumber != null: { + GetOrAddNoteGroups(lastLineNumber.Value).Last().HasJump = true; + break; + } + + // TODO: Add mode for area tests + /* + case AreaReport a when ???: { + var start = GetOrAddNotesLists(a.StartLineNumber); + start.Add(new List { a.Type + " start" }); + start.Add(new List()); - var values = GetOrAddValues(step.LineNumber); - if (values.Count == 0) - values.Add(new List()); + var end = GetOrAddNotesLists(a.EndLineNumber); + end.Add(new List { a.Type + " end" }); + end.Add(new List()); + break; + } + */ + } - values.Last().Add(step.Name != null ? $"{step.Name}: {step.Value}" : step.Value); } - return valuesByLineNumber - .Where(p => p.Value.Any(v => v.Any())) + return groupsByLineNumber + .Select(gs => ( + line: gs.Key, + notes: string.Join(" ", gs.Value.Where(g => !g.IsEmpty).Select(g => g.ToString())) + )) + .Where(x => x.notes.Length > 0) .ToDictionary( - p => p.Key, - p => string.Join("; ", p.Value.Where(v => v.Any()).Select(v => string.Join(", ", v))) + x => x.line, + x => x.notes ); } @@ -73,33 +110,70 @@ private static IEnumerable ExtractFlowSteps(string output) { // non-value step var lineNumber = item.GetInt32(); lastLineNumber = lineNumber; - yield return new(lineNumber); + yield return new LineStep(lineNumber); + break; + } + + case JsonValueKind.String when item.GetString() == "j": { + yield return new JumpStep(); break; } case JsonValueKind.Object: { - var exception = item.GetProperty("exception").GetString(); - yield return new(lastLineNumber, exception, "exception"); + var exception = item.GetProperty("exception").GetString()!; + yield return new ValueStep(lastLineNumber, exception, "exception"); break; } - case JsonValueKind.Array: { + case JsonValueKind.Array when item[0].ValueKind == JsonValueKind.Number: { var lineNumber = item[0].GetInt32(); var name = item.GetArrayLength() > 2 ? item[2].GetString() : null; var value = item[1].ValueKind == JsonValueKind.String ? item[1].GetString()! : item[1].GetInt32().ToString(); - yield return new(lineNumber, value, name); + yield return new ValueStep(lineNumber, value, name); + break; + } + + case JsonValueKind.Array when item[0].ValueKind == JsonValueKind.String: { + var type = item[0].GetString()! switch { + "l" => "loop", + "m" => "method", + var t => throw new ("Unknown area type: " + t) + }; + var startLineNumber = item[1].GetInt32(); + var endLineNumber = item[2].GetInt32(); + + yield return new AreaReport(type, startLineNumber, endLineNumber); break; } default: - throw new($"Unknown step value kind: ${item}"); + throw new($"Unknown step value kind: {item}"); } } } - private record FlowStep(int LineNumber, string? Value = null, string? Name = null); + private record FlowStep(); + private record LineStep(int LineNumber): FlowStep; + private record JumpStep() : FlowStep; + private record ValueStep(int LineNumber, string Value, string? Name) : FlowStep; + private record AreaReport(string Type, int StartLineNumber, int EndLineNumber) : FlowStep; + + private enum AssertCommentMode { + Values, + Jumps + } + + private class LineNoteGroup { + public IList Values { get; } = new List(); + public bool HasJump { get; set; } + public bool IsEmpty => !Values.Any() && !HasJump; + public override string ToString() => string.Join(" ", new[] { + Values.Any() ? $"[{string.Join(", ", Values)}]" : null, + HasJump ? "jump🠊" : null + }.Where(p => p != null)); + } } } diff --git a/source/Tests/Execution/RegressionTests.cs b/source/Tests/Execution/RegressionTests.cs index d44b995d9..4d93fd55f 100644 --- a/source/Tests/Execution/RegressionTests.cs +++ b/source/Tests/Execution/RegressionTests.cs @@ -3,20 +3,33 @@ using SharpLab.Tests.Execution.Internal; using SharpLab.Tests.Internal; using Xunit; +using Xunit.Abstractions; namespace SharpLab.Tests.Execution { [Collection(TestCollectionNames.Execution)] public class RegressionTests { + public RegressionTests(ITestOutputHelper output) { + // TestDiagnosticLog.Enable(output); + } + [Theory] [InlineData("CertainLoop.cs")] [InlineData("FSharpNestedLambda.fs", LanguageNames.FSharp)] [InlineData("NestedAnonymousObject.cs")] - [InlineData("ReturnRef.cs")] + [InlineData("RefReturn.cs")] + [InlineData("RefStructReturningThis.cs")] [InlineData("CatchWithNameSameLineAsClosingTryBracket.cs")] [InlineData("MoreThanFourArguments.cs")] [InlineData("InitOnlyProperty.cs")] [InlineData("TopLevelLocalConstant.cs")] [InlineData("LambdaParameterList.vb", LanguageNames.VisualBasic)] + [InlineData("UnsafePointers.cs")] + [InlineData("UnsafeFunctionPointerCall.cs")] + [InlineData("DynamicPassedToGeneric.cs")] + [InlineData("UsingDeclarationsWith2Declarations.cs")] + [InlineData("UsingDeclarationsWith3Declarations.cs")] + [InlineData("NoILRewriting.cs")] + [InlineData("ConstrainedGeneric.cs")] public async Task Execution_DoesNotFail(string codeFileName, string languageName = LanguageNames.CSharp) { // Arrange var code = await TestCode.FromCodeOnlyFileAsync("Regression/" + codeFileName); @@ -57,7 +70,7 @@ public static void Main(string[] args) { [InlineData("void M(ref Span s) {}", "var s = new Span(); M(ref s)")] [InlineData("void M(ReadOnlySpan s) {}", "M(new ReadOnlySpan())")] [InlineData("void M(ref ReadOnlySpan s) {}", "var s = new ReadOnlySpan(); M(ref s)")] - public async Task SlowUpdate_DoesNotFail_OnSpanArguments(string methodCode, string methodCallCode) { + public async Task Execution_DoesNotFail_OnSpanArguments(string methodCode, string methodCallCode) { // Arrange var code = @" using System; @@ -75,5 +88,18 @@ public static void Main() { // Assert Assert.DoesNotMatch("Exception:", output); } + + [Theory] + [InlineData("NoAssembly.il")] + public async Task Execution_ReturnsBadImageFormatException_ForIncorrectIL(string codeFileName) { + // Arrange + var code = await TestCode.FromCodeOnlyFileAsync("Regression/" + codeFileName); + + // Act + var output = await ContainerTestDriver.CompileAndExecuteAsync(code, LanguageNames.IL); + + // Assert + Assert.Matches("""title":"Exception","value":"System.BadImageFormatException""", output); + } } } diff --git a/source/Tests/Execution/TestCode/Flow/Jumps/Call.InternalAndExternal.cs b/source/Tests/Execution/TestCode/Flow/Jumps/Call.InternalAndExternal.cs new file mode 100644 index 000000000..c084d8bfd --- /dev/null +++ b/source/Tests/Execution/TestCode/Flow/Jumps/Call.InternalAndExternal.cs @@ -0,0 +1,10 @@ +using System; + +M(); // jump🠊 +Console.WriteLine("a"); + +/* needs not-a-call at the end */ +var x = 1; + +void M() { +} // jump🠊 \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Flow/Values/Argument.Array.Generic.cs b/source/Tests/Execution/TestCode/Flow/Values/Argument.Array.Generic.cs new file mode 100644 index 000000000..50b526d3c --- /dev/null +++ b/source/Tests/Execution/TestCode/Flow/Values/Argument.Array.Generic.cs @@ -0,0 +1,4 @@ +M(new int[] { 1, 2, 3 }); + +void M(T[] x) { // [x: { 1, 2, 3 }] +} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Flow/Values/Loop.For.10Iterations.cs b/source/Tests/Execution/TestCode/Flow/Values/Loop.For.10Iterations.cs index f5b59eb03..e6c5532d1 100644 --- a/source/Tests/Execution/TestCode/Flow/Values/Loop.For.10Iterations.cs +++ b/source/Tests/Execution/TestCode/Flow/Values/Loop.For.10Iterations.cs @@ -1,6 +1,6 @@ public static class Program { public static void Main() { - for (var i = 0; i < 10; i++) { // [i: 0; i: 1; i: 2; …] + for (var i = 0; i < 10; i++) { // [i: 0] [i: 1] [i: 2] [i: 3] [i: 4] [i: 5] [i: 6] [i: 7] [i: 8] [i: 9] [i: 10] } } } \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Flow/Values/Variable.LongName.cs b/source/Tests/Execution/TestCode/Flow/Values/Variable.LongName.cs index 8c57de671..50a9b4ace 100644 --- a/source/Tests/Execution/TestCode/Flow/Values/Variable.LongName.cs +++ b/source/Tests/Execution/TestCode/Flow/Values/Variable.LongName.cs @@ -1,5 +1,5 @@ public static class Program { public static void Main() { - var abcdefghijklmnoprstquvwxyz = 0; // [abcdefghi…: 0] + var abcdefghijklmnoprstquvwxyz = 0; // [abcdefghijklmnoprst…: 0] } } \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Flow/Values/Variable.MultipleDeclarationsOnTheSameLine.cs b/source/Tests/Execution/TestCode/Flow/Values/Variable.MultipleDeclarationsOnTheSameLine.cs index 38943ddc7..2c600e8d0 100644 --- a/source/Tests/Execution/TestCode/Flow/Values/Variable.MultipleDeclarationsOnTheSameLine.cs +++ b/source/Tests/Execution/TestCode/Flow/Values/Variable.MultipleDeclarationsOnTheSameLine.cs @@ -1,5 +1,5 @@ public static class Program { public static void Main() { - int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0; // [a: 0, b: 0, c: 0, …] + int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0; // [a: 0, b: 0, c: 0, d: 0, e: 0, f: 0, g: 0, h: 0, i: 0] } } \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs2output b/source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs similarity index 81% rename from source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs2output rename to source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs index 046a8b4a7..620e06cb8 100644 --- a/source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/Heap/Int32.cs @@ -7,6 +7,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory","title":"System.Int32 at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"m_value","offset":16,"length":4}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,5,0,0,0,0,0,0,0]} \ No newline at end of file +#{"type":"inspection:memory","title":"System.Int32 at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"m_value","offset":16,"length":4}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,5,0,0,0,0,0,0,0]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/Heap/Null.cs2output b/source/Tests/Execution/TestCode/Inspect/Heap/Null.cs similarity index 90% rename from source/Tests/Execution/TestCode/Inspect/Heap/Null.cs2output rename to source/Tests/Execution/TestCode/Inspect/Heap/Null.cs index 94212c031..a0d10e1ab 100644 --- a/source/Tests/Execution/TestCode/Inspect/Heap/Null.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/Heap/Null.cs @@ -1,14 +1,16 @@ -using System; - -public static class Program { - public static void Main() { - Inspect.Heap((object)null); - } -} - -#=> - -Exception: System.Exception: Inspect.Heap can't inspect null, as it does not point to a valid location on the heap. - at SharpLab.Server.Execution.Runtime.MemoryBytesInspector.InspectHeap(Object object) - at Inspect.Heap(Object object) - at Program.Main() \ No newline at end of file +using System; + +public static class Program { + public static void Main() { + Inspect.Heap((object)null); + } +} + +/* output + +Exception: System.Exception: Inspect.Heap can't inspect null, as it does not point to a valid location on the heap. + at SharpLab.Server.Execution.Runtime.MemoryBytesInspector.InspectHeap(Object object) + at Inspect.Heap(Object object) + at Program.Main() + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs2output b/source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs similarity index 91% rename from source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs2output rename to source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs index aa2f95434..bc8eedcc7 100644 --- a/source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/Heap/Simple.cs @@ -12,6 +12,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory","title":"C at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0]} \ No newline at end of file +#{"type":"inspection:memory","title":"C at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs2output b/source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs similarity index 92% rename from source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs2output rename to source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs index bf5ad5e79..754b3e80f 100644 --- a/source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/Heap/Struct.Nested.cs @@ -18,6 +18,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory","title":"S at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1},{"name":"n","offset":24,"length":5,"nested":[{"name":"an","offset":24,"length":4},{"name":"bn","offset":28,"length":1}]}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0]} \ No newline at end of file +#{"type":"inspection:memory","title":"S at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1},{"name":"n","offset":24,"length":5,"nested":[{"name":"an","offset":24,"length":4},{"name":"bn","offset":28,"length":1}]}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs2output b/source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs similarity index 91% rename from source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs2output rename to source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs index dd25ac81f..3525df27b 100644 --- a/source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/Heap/Struct.cs @@ -12,6 +12,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory","title":"S at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0]} \ No newline at end of file +#{"type":"inspection:memory","title":"S at 0x","labels":[{"name":"header","offset":0,"length":8},{"name":"type handle","offset":8,"length":8},{"name":"a","offset":16,"length":4},{"name":"b","offset":20,"length":1}],"data":[0,0,0,0,0,0,0,0,,,,,,,,,1,0,0,0,2,0,0,0]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Arrays.cs b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Arrays.cs index a700abb97..d4aca5071 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Arrays.cs +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Arrays.cs @@ -1,9 +1,9 @@ Inspect.MemoryGraph(new[] { 1, 2, 3 }); Inspect.MemoryGraph(new[] { "a", "b", "c" }); -/* Output +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"Int32[] ref"}],"heap":[{"id":2,"title":"Int32[]","value":"{ 1, 2, 3 }","nestedNodes":[{"id":3,"title":"0","value":"1"},{"id":4,"title":"1","value":"2"},{"id":5,"title":"2","value":"3"}]}],"references":[{"from":1,"to":2}]} +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"Int32[] ref"}],"heap":[{"id":2,"title":"Int32[]","value":"{ 1, 2, 3 }","nestedNodes":[{"id":3,"title":"0","value":"1"},{"id":4,"title":"1","value":"2"},{"id":5,"title":"2","value":"3"}]}],"references":[{"from":1,"to":2}]} #{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"String[] ref"}],"heap":[{"id":2,"title":"String[]","value":"{ a, b, c }","nestedNodes":[{"id":3,"title":"0","value":"String ref"},{"id":5,"title":"1","value":"String ref"},{"id":7,"title":"2","value":"String ref"}]},{"id":4,"title":"String","value":"a"},{"id":6,"title":"String","value":"b"},{"id":8,"title":"String","value":"c"}],"references":[{"from":3,"to":4},{"from":5,"to":6},{"from":7,"to":8},{"from":1,"to":2}]} */ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs2output b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs similarity index 87% rename from source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs2output rename to source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs index dcac811c6..c537c846a 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/DateTime.cs @@ -7,6 +7,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"01.01.2000 00:00:00","nestedNodes":[{"id":2,"title":"_dateData","value":"630822816000000000"}]}],"heap":[],"references":[]} \ No newline at end of file +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"01.01.2000 00:00:00","nestedNodes":[{"id":2,"title":"_dateData","value":"630822816000000000"}]}],"heap":[],"references":[]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs2output b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs similarity index 70% rename from source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs2output rename to source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs index 2ade4dff1..49f6fd53c 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Int32.cs @@ -7,6 +7,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":4,"title":null,"value":"1"}],"heap":[],"references":[]} \ No newline at end of file +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":4,"title":null,"value":"1"}],"heap":[],"references":[]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs2output b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs similarity index 90% rename from source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs2output rename to source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs index 8416a3590..4b9ad5d04 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Null.cs @@ -6,6 +6,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"null"}],"heap":[],"references":[]} \ No newline at end of file +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"null"}],"heap":[],"references":[]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs2output b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs similarity index 76% rename from source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs2output rename to source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs index ff28a2809..3ebadf842 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/String.cs @@ -7,6 +7,8 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"String ref"}],"heap":[{"id":2,"title":"String","value":"a"}],"references":[{"from":1,"to":2}]} \ No newline at end of file +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":8,"title":null,"value":"String ref"}],"heap":[{"id":2,"title":"String","value":"a"}],"references":[{"from":1,"to":2}]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs2output b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs similarity index 85% rename from source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs2output rename to source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs index 0422cf500..c81263501 100644 --- a/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs2output +++ b/source/Tests/Execution/TestCode/Inspect/MemoryGraph/Variables.cs @@ -11,7 +11,9 @@ public static void Main() { } } -#=> +/* output -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":16,"size":4,"title":"a","value":"1"},{"id":2,"offset":0,"size":8,"title":"c","value":"String ref"}],"heap":[{"id":3,"title":"String","value":"c"}],"references":[{"from":2,"to":3}]} -#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":4,"title":"b","value":"2"}],"heap":[],"references":[]} \ No newline at end of file +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":16,"size":4,"title":"a","value":"1"},{"id":2,"offset":0,"size":8,"title":"c","value":"String ref"}],"heap":[{"id":3,"title":"String","value":"c"}],"references":[{"from":2,"to":3}]} +#{"type":"inspection:memory-graph","stack":[{"id":1,"offset":0,"size":4,"title":"b","value":"2"}],"heap":[],"references":[]} + +*/ \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/ConstrainedGeneric.cs b/source/Tests/Execution/TestCode/Regression/ConstrainedGeneric.cs new file mode 100644 index 000000000..84c654f94 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/ConstrainedGeneric.cs @@ -0,0 +1,15 @@ +Test(new S()); + +static int Test(T value) + where T : struct, I +{ + return value.Value; +} + +interface I { + int Value { get; } +} + +struct S : I { + public int Value => 1; +} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/DynamicPassedToGeneric.cs b/source/Tests/Execution/TestCode/Regression/DynamicPassedToGeneric.cs new file mode 100644 index 000000000..eb83c5bc8 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/DynamicPassedToGeneric.cs @@ -0,0 +1,5 @@ +C.Generic((dynamic)1); + +class C { + public static void Generic(T _) {} +} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/NoAssembly.il b/source/Tests/Execution/TestCode/Regression/NoAssembly.il new file mode 100644 index 000000000..0fd1b7147 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/NoAssembly.il @@ -0,0 +1,5 @@ +.method static void M () cil managed +{ + .entrypoint + ret +} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/NoILRewriting.cs b/source/Tests/Execution/TestCode/Regression/NoILRewriting.cs new file mode 100644 index 000000000..1e39ebd40 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/NoILRewriting.cs @@ -0,0 +1,5 @@ +using System; +using SharpLab.Runtime; + +[assembly: NoILRewriting] +Console.WriteLine("👍"); \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/ReturnRef.cs b/source/Tests/Execution/TestCode/Regression/RefReturn.cs similarity index 100% rename from source/Tests/Execution/TestCode/Regression/ReturnRef.cs rename to source/Tests/Execution/TestCode/Regression/RefReturn.cs diff --git a/source/Tests/Execution/TestCode/Regression/RefStructReturningThis.cs b/source/Tests/Execution/TestCode/Regression/RefStructReturningThis.cs new file mode 100644 index 000000000..16a96b554 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/RefStructReturningThis.cs @@ -0,0 +1,2 @@ +new S().M(); +ref struct S { public S M() => this; } \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/UnsafeFunctionPointerCall.cs b/source/Tests/Execution/TestCode/Regression/UnsafeFunctionPointerCall.cs new file mode 100644 index 000000000..13fbabdd6 --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/UnsafeFunctionPointerCall.cs @@ -0,0 +1,6 @@ +unsafe { + delegate* m = &M; + m(); +} + +static void M() {} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Compilation/UnsafeKeyword.cs b/source/Tests/Execution/TestCode/Regression/UnsafePointers.cs similarity index 89% rename from source/Tests/Execution/TestCode/Compilation/UnsafeKeyword.cs rename to source/Tests/Execution/TestCode/Regression/UnsafePointers.cs index 667448d19..2da803443 100644 --- a/source/Tests/Execution/TestCode/Compilation/UnsafeKeyword.cs +++ b/source/Tests/Execution/TestCode/Regression/UnsafePointers.cs @@ -2,6 +2,7 @@ public static class Program { public static void Main() { unsafe { var node = new Node(); + Node* a = &node; } } diff --git a/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith2Declarations.cs b/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith2Declarations.cs new file mode 100644 index 000000000..8700c9a0d --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith2Declarations.cs @@ -0,0 +1,9 @@ +using System; + +using var a = new Disposable(); +using var b = new Disposable(); + +public class Disposable : IDisposable +{ + public void Dispose() { } +} \ No newline at end of file diff --git a/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith3Declarations.cs b/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith3Declarations.cs new file mode 100644 index 000000000..17c96bafc --- /dev/null +++ b/source/Tests/Execution/TestCode/Regression/UsingDeclarationsWith3Declarations.cs @@ -0,0 +1,10 @@ +using System; + +using var a = new Disposable(); +using var b = new Disposable(); +using var c = new Disposable(); + +public class Disposable : IDisposable +{ + public void Dispose() { } +} \ No newline at end of file diff --git a/source/Tests/Execution/Unit/StdoutReaderTests.cs b/source/Tests/Execution/Unit/StdoutReaderTests.cs index f2cdbf2dd..14188f859 100644 --- a/source/Tests/Execution/Unit/StdoutReaderTests.cs +++ b/source/Tests/Execution/Unit/StdoutReaderTests.cs @@ -36,7 +36,7 @@ public async Task ReadOutputAsync_DetectsOutputBoundariesCorrectly(string[] segm ); Assert.Equal(expectedOutput, Encoding.UTF8.GetString(result.Output.Span)); - Assert.True(result.IsOutputReadSuccess); + Assert.True(result.IsSuccess); } private class Utf8SegmentedAsyncStream : Stream { diff --git a/source/Tests/ExplanationTests.cs b/source/Tests/ExplanationTests.cs index 30937ff2a..810b64dd5 100644 --- a/source/Tests/ExplanationTests.cs +++ b/source/Tests/ExplanationTests.cs @@ -17,11 +17,15 @@ public class ExplanationTests { [InlineData("nameof expression", "class C { string f = nameof(C); }", "nameof(C)")] [InlineData("declaration with a private protected access modifier", "class C { private protected string f; }", "private protected string f;")] public async Task SlowUpdate_ExplainsCSharpFeature(string name, string providedCode, string expectedCode) { + // Arrange var driver = await NewTestDriverAsync(); driver.SetText(providedCode); + // Act var result = await driver.SendSlowUpdateAsync(); + // Assert + Assert.NotNull(result.ExtensionResult); var explanation = Assert.Single(result.ExtensionResult); // some spaces are expected -- currently extra spaces are trimmed by JS Assert.Equal(expectedCode, explanation.Code.Trim()); @@ -34,11 +38,15 @@ public async Task SlowUpdate_ExplainsCSharpFeature(string name, string providedC [InlineData("class C { async void A() { var x = 5; } }", "async void A() { … }")] [InlineData("class C { async void A() {} }", "async void A() {}")] public async Task SlowUpdate_DoesNotIncludeBlockContentsInExplanationCode(string source, string expected) { + // Arrange var driver = await NewTestDriverAsync(); driver.SetText(source); + // Act var result = await driver.SendSlowUpdateAsync(); + // Assert + Assert.NotNull(result.ExtensionResult); var explanation = Assert.Single(result.ExtensionResult); // some spaces are expected -- currently extra spaces are trimmed by JS Assert.Equal(expected, explanation.Code.Trim()); @@ -48,11 +56,15 @@ public async Task SlowUpdate_DoesNotIncludeBlockContentsInExplanationCode(string [InlineData("class C { async void A(int a) {} }", "async void A(…) {}")] [InlineData("class C { async void A() {} }", "async void A() {}")] public async Task SlowUpdate_DoesNotIncludeParameterListsInExplanationCode(string source, string expected) { + // Arrange var driver = await NewTestDriverAsync(); driver.SetText(source); + // Act var result = await driver.SendSlowUpdateAsync(); + // Assert + Assert.NotNull(result.ExtensionResult); var explanation = Assert.Single(result.ExtensionResult); // some spaces are expected -- currently extra spaces are trimmed by JS Assert.Equal(expected, explanation.Code.Trim()); diff --git a/source/Tests/Internal/TestAssemblyLog.cs b/source/Tests/Internal/TestAssemblyLog.cs deleted file mode 100644 index 8554130ea..000000000 --- a/source/Tests/Internal/TestAssemblyLog.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Text.RegularExpressions; -using SharpLab.Server.Common.Diagnostics; -using Xunit.Abstractions; - -namespace SharpLab.Tests.Internal { - public static class TestAssemblyLog { - [Conditional("DEBUG")] - public static void Enable(ITestOutputHelper output) { - var test = ((ITest) - output - .GetType() - .GetField("test", BindingFlags.Instance | BindingFlags.NonPublic)! - .GetValue(output)! - ); - var testType = test.TestCase.TestMethod.TestClass.Class.ToRuntimeType(); - var testName = test.DisplayName.Replace(testType.FullName + ".", ""); - - var safeTestName = Regex.Replace(testName, "[^a-zA-Z._-]+", "_"); - if (safeTestName.Length > 100) - safeTestName = safeTestName.Substring(0, 100) + "-" + safeTestName.GetHashCode(); - - var basePath = Path.Combine( - AppContext.BaseDirectory, "assembly-log", - testType.Name, safeTestName - ); - #if DEBUG - AssemblyLog.Enable(stepName => Path.Combine(basePath, stepName)); - #endif - } - } -} diff --git a/source/Tests/Internal/TestCode.cs b/source/Tests/Internal/TestCode.cs index e78de9f43..7c400d6a6 100644 --- a/source/Tests/Internal/TestCode.cs +++ b/source/Tests/Internal/TestCode.cs @@ -21,38 +21,40 @@ public class TestCode { { "output", TargetNames.Run }, }; + private static readonly IReadOnlyDictionary CommentMarkers = new Dictionary(StringComparer.OrdinalIgnoreCase) { + { LanguageNames.CSharp, ("/*", "*/") }, + { LanguageNames.VisualBasic, ("/*", "*/") }, // TODO: Sort out + { LanguageNames.FSharp, ("(*", "*)") }, + { LanguageNames.IL, ("/*", "*/") }, + }; + + private static readonly bool ShouldUpdateOnAssert = Environment.GetEnvironmentVariable("SHARPLAB_TEST_UPDATE_SNAPSHOTS") == "true"; + public string Original { get; } public string SourceLanguageName { get; } public string TargetName { get; } private readonly string _expected; + private readonly string? _snapshotFilePath; - public TestCode(string original, string expected, string sourceLanguageName, string targetName) { + public TestCode(string original, string expected, string sourceLanguageName, string targetName, string? snapshotFilePath = null) { Original = original; SourceLanguageName = sourceLanguageName; TargetName = targetName; _expected = expected; + _snapshotFilePath = snapshotFilePath; } public static Task FromCodeOnlyFileAsync(string relativePath, [CallerFilePath] string callerFilePath = "") { - var testBasePath = Path.GetDirectoryName(callerFilePath)!; - var fullPath = Path.Combine(AppContext.BaseDirectory, testBasePath, "TestCode", relativePath); - - return File.ReadAllTextAsync(fullPath); + return File.ReadAllTextAsync(GetFullPath(relativePath, callerFilePath)); } public static async Task FromFileAsync(string relativePath, [CallerFilePath] string callerFilePath = "") { - var content = await FromCodeOnlyFileAsync(relativePath, callerFilePath); + var fullPath = GetFullPath(relativePath, callerFilePath); + var content = await File.ReadAllTextAsync(fullPath); var extension = Path.GetExtension(relativePath); - return FromContent(content, extension); - } - - private static TestCode FromContent(string content, string extension) { - if (extension.Contains("2")) - return FromContentFormatV1(content, extension); - - var split = Regex.Matches(content, @"[/(]\* (?\S+)").Last(); + var split = Regex.Matches(content, @"^[/(]\* (?\S+)", RegexOptions.Multiline).Last(); var from = LanguageAndTargetMap[extension.TrimStart('.')]; var to = LanguageAndTargetMap[split.Groups["to"].Value]; @@ -62,23 +64,24 @@ private static TestCode FromContent(string content, string extension) { @"^\s+|\s*\*[/)]\s*$", "" ); - return new TestCode(code, expected, from, to); + return new TestCode(code, expected, from, to, fullPath); } - private static TestCode FromContentFormatV1(string content, string extension) { - var parts = content.Split("#=>"); - var code = parts[0].Trim(); - var expected = parts[1].Trim(); - // ReSharper disable once PossibleNullReferenceException - var fromTo = extension.TrimStart('.').Split('2').Select(x => LanguageAndTargetMap[x]).ToList(); - - return new TestCode(code, expected, fromTo[0], fromTo[1]); + private static string GetFullPath(string relativePath, string callerFilePath) { + var testBasePath = Path.GetDirectoryName(callerFilePath)!; + return Path.Combine(AppContext.BaseDirectory, testBasePath, "TestCode", relativePath); } - public void AssertIsExpected(string? result, ITestOutputHelper output) { + public async Task AssertIsExpectedAsync(string? result, ITestOutputHelper output) { var cleanResult = RemoveNonDeterminism(result?.Trim()); output.WriteLine(cleanResult ?? ""); + + if (_snapshotFilePath is {} path && cleanResult is {} actual && ShouldUpdateOnAssert) { + await UpdateFileAsync(path, actual); + return; + } + Assert.Equal(NormalizeNewLines(_expected), NormalizeNewLines(cleanResult)); } @@ -113,5 +116,13 @@ public void AssertIsExpected(string? result, ITestOutputHelper output) { private string? NormalizeNewLines(string? value) { return value?.Replace("\r\n", "\n"); } + + private async Task UpdateFileAsync(string path, string actual) { + var (commentStart, commentEnd) = CommentMarkers[SourceLanguageName]; + var targetExtension = LanguageAndTargetMap.First(p => p.Value == TargetName).Key; + + var updatedContent = $"{Original}\r\n\r\n{commentStart} {targetExtension}\r\n\r\n{actual}\r\n\r\n{commentEnd}"; + await File.WriteAllTextAsync(path, updatedContent); + } } } diff --git a/source/Tests/Internal/TestDiagnosticLog.cs b/source/Tests/Internal/TestDiagnosticLog.cs new file mode 100644 index 000000000..68d0a07b5 --- /dev/null +++ b/source/Tests/Internal/TestDiagnosticLog.cs @@ -0,0 +1,39 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Text.RegularExpressions; +using SharpLab.Server.Common.Diagnostics; +using Xunit.Abstractions; + +namespace SharpLab.Tests.Internal; + +public static class TestDiagnosticLog { + [Conditional("DEBUG")] + public static void Enable(ITestOutputHelper output) { + var test = ((ITest) + output + .GetType() + .GetField("test", BindingFlags.Instance | BindingFlags.NonPublic)! + .GetValue(output)! + ); + var testType = test.TestCase.TestMethod.TestClass.Class.ToRuntimeType(); + var testName = test.DisplayName.Replace(testType.FullName + ".", ""); + + string SafePath(string name) => Regex.Replace(name, @"[^a-zA-Z\d._\-]+", "_"); + var safeTestName = SafePath(testName); + if (safeTestName.Length > 100) + safeTestName = safeTestName.Substring(0, 100) + "-" + safeTestName.GetHashCode(); + + var basePath = Path.Combine( + AppContext.BaseDirectory, "assembly-log", + testType.Name, safeTestName + ); + #if DEBUG + DiagnosticLog.Enable( + output.WriteLine, + stepName => Path.Combine(basePath, SafePath(stepName)) + ); + #endif + } +} diff --git a/source/Tests/Internal/TestDriverFactory.cs b/source/Tests/Internal/TestDriverFactory.cs index 673453ebe..5ccd355a2 100644 --- a/source/Tests/Internal/TestDriverFactory.cs +++ b/source/Tests/Internal/TestDriverFactory.cs @@ -2,19 +2,19 @@ using MirrorSharp.Testing; using SharpLab.Server.Common; -namespace SharpLab.Tests.Internal { - public static class TestDriverFactory { - public static async Task FromCodeAsync(TestCode code, string optimize = Optimize.Release) { - var driver = TestEnvironment.NewDriver(); - await driver.SendSetOptionsAsync(code.SourceLanguageName, code.TargetName, optimize); - driver.SetText(code.Original); - return driver; - } +namespace SharpLab.Tests.Internal; - public static async Task FromCodeAsync(string code, string sourceLanguageName, string targetName, string optimize = Optimize.Release) { - var driver = TestEnvironment.NewDriver().SetText(code); - await driver.SendSetOptionsAsync(sourceLanguageName, targetName, optimize); - return driver; - } +public static class TestDriverFactory { + public static async Task FromCodeAsync(TestCode code, string optimize = Optimize.Release) { + var driver = TestEnvironment.NewDriver(); + await driver.SendSetOptionsAsync(code.SourceLanguageName, code.TargetName, optimize); + driver.SetText(code.Original); + return driver; + } + + public static async Task FromCodeAsync(string code, string sourceLanguageName, string targetName, string optimize = Optimize.Release) { + var driver = TestEnvironment.NewDriver().SetText(code); + await driver.SendSetOptionsAsync(sourceLanguageName, targetName, optimize); + return driver; } } diff --git a/source/Tests/Internal/TestEnvironment.cs b/source/Tests/Internal/TestEnvironment.cs index 4504fe1be..1f60aab1e 100644 --- a/source/Tests/Internal/TestEnvironment.cs +++ b/source/Tests/Internal/TestEnvironment.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using Autofac; using Autofac.Extensions.DependencyInjection; using MirrorSharp; @@ -6,30 +7,36 @@ using MirrorSharp.Advanced.EarlyAccess; using MirrorSharp.Testing; using SharpLab.Server; +using SharpLab.Server.Common; -namespace SharpLab.Tests.Internal { - public static class TestEnvironment { - public static ILifetimeScope Container { get; } = ((Func)(() => { - Environment.SetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_URL", "http://localhost/test"); - Environment.SetEnvironmentVariable("SHARPLAB_LOCAL_SECRETS_ContainerHostAuthorizationToken", "_"); - Environment.SetEnvironmentVariable("SHARPLAB_WEBAPP_NAME", "sl-test"); - Environment.SetEnvironmentVariable("SHARPLAB_CACHE_PATH_PREFIX", "test"); +namespace SharpLab.Tests.Internal; - var host = Program.CreateHostBuilder(new string[0]).Build(); - return host.Services.GetAutofacRoot(); - }))(); +public static class TestEnvironment { + public static ILifetimeScope Container { get; } = ((Func)(() => { + var host = Program.CreateHostBuilder(new string[0]).Build(); + return host.Services.GetAutofacRoot(); + }))(); - public static MirrorSharpOptions MirrorSharpOptions { get; } = Startup.CreateMirrorSharpOptions(Container); + public static MirrorSharpOptions MirrorSharpOptions { get; } = Startup.CreateMirrorSharpOptions(Container); - public static MirrorSharpServices MirrorSharpServices { get; } = new MirrorSharpServices { - SetOptionsFromClient = Container.ResolveOptional(), - SlowUpdate = Container.ResolveOptional(), - RoslynSourceTextGuard = Container.ResolveOptional(), - RoslynCompilationGuard = Container.ResolveOptional(), - ConnectionSendViewer = Container.ResolveOptional(), - ExceptionLogger = Container.ResolveOptional() - }; + public static MirrorSharpServices MirrorSharpServices { get; } = new MirrorSharpServices { + SetOptionsFromClient = Container.ResolveOptional(), + SlowUpdate = Container.ResolveOptional(), + RoslynSourceTextGuard = Container.ResolveOptional(), + RoslynCompilationGuard = Container.ResolveOptional(), + ConnectionSendViewer = Container.ResolveOptional(), + ExceptionLogger = Container.ResolveOptional() + }; - public static MirrorSharpTestDriver NewDriver() => MirrorSharpTestDriver.New(MirrorSharpOptions, MirrorSharpServices); + [ModuleInitializer] + public static void Initialize() { + Environment.SetEnvironmentVariable("SHARPLAB_CONTAINER_HOST_URL", "http://localhost/test"); + Environment.SetEnvironmentVariable("SHARPLAB_LOCAL_SECRETS_ContainerHostAuthorizationToken", "_"); + Environment.SetEnvironmentVariable("SHARPLAB_WEBAPP_NAME", "sl-test"); + Environment.SetEnvironmentVariable("SHARPLAB_CACHE_PATH_PREFIX", "test"); + + DotEnv.Load(); } + + public static MirrorSharpTestDriver NewDriver() => MirrorSharpTestDriver.New(MirrorSharpOptions, MirrorSharpServices); } diff --git a/source/Tests/Internal/TestModule.cs b/source/Tests/Internal/TestModule.cs index e36684173..9ee9aa880 100644 --- a/source/Tests/Internal/TestModule.cs +++ b/source/Tests/Internal/TestModule.cs @@ -26,7 +26,7 @@ protected override void Load(ContainerBuilder builder) { .SingleInstance(); var configuration = new ConfigurationBuilder() - .AddInMemoryCollection(new Dictionary { + .AddInMemoryCollection(new Dictionary { { "App:Explanations:Urls:CSharp", "http://testdata/language-syntax-explanations/csharp.yml" }, { "App:Explanations:UpdatePeriod", "01:00:00" } }) diff --git a/source/Tests/Properties/AssemblyInfo.cs b/source/Tests/Properties/AssemblyInfo.cs index d111d06b6..0a808e81e 100644 --- a/source/Tests/Properties/AssemblyInfo.cs +++ b/source/Tests/Properties/AssemblyInfo.cs @@ -2,16 +2,16 @@ using Microsoft.Extensions.Logging; using MirrorSharp.Advanced; using SharpLab.Container.Manager.Internal; +using SharpLab.Server.Caching; using SharpLab.Server.Caching.Internal; using SharpLab.Server.Execution.Container; -using SharpLab.Server.Monitoring; using SourceMock; [assembly: GenerateMocksForTypes( typeof(IWorkSession), typeof(IRoslynSession), typeof(IDateTimeProvider), - typeof(IMonitor), + typeof(ICachingTracker), typeof(ILogger<>), typeof(IResultCacheStore), typeof(IContainerClient), diff --git a/source/Tests/Tests.csproj b/source/Tests/Tests.csproj index 72acc4c6d..36f7f5329 100644 --- a/source/Tests/Tests.csproj +++ b/source/Tests/Tests.csproj @@ -1,6 +1,6 @@ - net6.0 + net9.0 SharpLab.Tests SharpLab.Tests false @@ -8,6 +8,8 @@ false AutoGeneratedProgram true + x64 + x64 @@ -36,15 +38,15 @@ - + - - + + - + @@ -54,6 +56,12 @@ + + + PreserveNewest + + + diff --git a/source/WebApp.Server/Assets/AssetsModule.cs b/source/WebApp.Server/Assets/AssetsModule.cs index 7f3b29c35..013b83e48 100644 --- a/source/WebApp.Server/Assets/AssetsModule.cs +++ b/source/WebApp.Server/Assets/AssetsModule.cs @@ -1,25 +1,25 @@ using System; using Autofac; -namespace SharpLab.WebApp.Server.Assets { - public class AssetsModule : Module { - protected override void Load(ContainerBuilder builder) { - string GetRequiredEnvironmentVariable(string key) => Environment.GetEnvironmentVariable(key) - ?? throw new Exception($"{key} was not found in the environment."); +namespace SharpLab.WebApp.Server.Assets; - var baseUrl = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_BASE_URL"); - var latestUrl = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_LATEST_URL_V2"); - builder.RegisterType() - .WithParameter(new NamedParameter("baseUrl", new Uri(baseUrl))) - .WithParameter(new NamedParameter("latestUrlAbsolute", new Uri(latestUrl))) - .As() - .SingleInstance(); +public class AssetsModule : Module { + protected override void Load(ContainerBuilder builder) { + string GetRequiredEnvironmentVariable(string key) => Environment.GetEnvironmentVariable(key) + ?? throw new Exception($"{key} was not found in the environment."); - var reloadToken = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_RELOAD_TOKEN"); - builder.RegisterType() - .WithParameter(new NamedParameter("reloadToken", reloadToken)) - .AsSelf() - .SingleInstance(); - } + var baseUrl = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_BASE_URL"); + var latestUrl = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_LATEST_URL_V2"); + builder.RegisterType() + .WithParameter(new NamedParameter("baseUrl", new Uri(baseUrl))) + .WithParameter(new NamedParameter("latestUrlAbsolute", new Uri(latestUrl))) + .As() + .SingleInstance(); + + var reloadToken = GetRequiredEnvironmentVariable("SHARPLAB_ASSETS_RELOAD_TOKEN"); + builder.RegisterType() + .WithParameter(new NamedParameter("reloadToken", reloadToken)) + .AsSelf() + .SingleInstance(); } } diff --git a/source/WebApp.Server/WebApp.Server.csproj b/source/WebApp.Server/WebApp.Server.csproj index d82effb90..3b3ff9124 100644 --- a/source/WebApp.Server/WebApp.Server.csproj +++ b/source/WebApp.Server/WebApp.Server.csproj @@ -1,6 +1,6 @@ - net6.0 + net9.0 SharpLab.WebApp.Server SharpLab.WebApp.Server true @@ -19,7 +19,7 @@ - + diff --git a/source/WebApp/.depcheckrc.json b/source/WebApp/.depcheckrc.json new file mode 100644 index 000000000..1f767f5fd --- /dev/null +++ b/source/WebApp/.depcheckrc.json @@ -0,0 +1,28 @@ +{ + "ignores": [ + "@babel/core", + "@babel/preset-env", + "@fontsource/*", + "@storybook/*", + "@types/applicationinsights-js", + "@types/css-font-loading-module", + "@types/jest", + "babel-loader", + "codemirror-addon-infotip", + "codemirror-addon-lint-fix", + "jest-environment-jsdom", + "less-loader", + "normalize.css", + + "depcheck", + "esbuild", + "http-server", + + "d3-force" + ], + "specials": [ + "bin", + "eslint", + "jest" + ] +} \ No newline at end of file diff --git a/source/WebApp/.eslintrc.json b/source/WebApp/.eslintrc.json index d8d63635d..c8ef926f6 100644 --- a/source/WebApp/.eslintrc.json +++ b/source/WebApp/.eslintrc.json @@ -15,7 +15,8 @@ "plugins": [ "@typescript-eslint", "import", - "react-hooks" + "react-hooks", + "storybook" ], "extends": [ "eslint:recommended", @@ -23,7 +24,8 @@ "plugin:@typescript-eslint/recommended", "plugin:import/errors", "plugin:import/warnings", - "plugin:react-hooks/recommended" + "plugin:react-hooks/recommended", + "plugin:storybook/recommended" ], "env": { "node": true @@ -45,10 +47,11 @@ "linebreak-style": ["warn", "windows"], "eol-last": ["warn", "never"], "object-curly-spacing": ["warn", "always"], + "key-spacing": ["warn", { "mode": "minimum" }], "arrow-parens": ["warn", "as-needed"], "dot-location": ["warn", "property"], "operator-linebreak": ["warn", "before"], - "func-style": ["warn", "declaration", { "allowArrowFunctions": true }], + "func-style": ["warn", "expression"], "prefer-object-spread": "warn", "no-mixed-operators": "warn", "space-infix-ops": "warn", @@ -97,7 +100,7 @@ "import/newline-after-import": "warn", "react-hooks/exhaustive-deps": ["warn", { - "additionalHooks": "useAsyncCallback" + "additionalHooks": "useAsyncCallback|useRecoilCallback" }] } } \ No newline at end of file diff --git a/source/WebApp/.gitattributes b/source/WebApp/.gitattributes new file mode 100644 index 000000000..254495cbd --- /dev/null +++ b/source/WebApp/.gitattributes @@ -0,0 +1 @@ +**/__snapshots__/**/* filter=lfs diff=lfs merge=lfs -text diff --git a/source/WebApp/.storybook/main.js b/source/WebApp/.storybook/main.js index 09fff6226..a8d249667 100644 --- a/source/WebApp/.storybook/main.js +++ b/source/WebApp/.storybook/main.js @@ -14,6 +14,9 @@ module.exports = { core: { builder: 'webpack5', }, + typescript: { + reactDocgen: false, + }, webpackFinal: async (config) => { config.resolve.symlinks = false; config.resolve.alias[ diff --git a/source/WebApp/.storybook/preview.js b/source/WebApp/.storybook/preview.js deleted file mode 100644 index c43379455..000000000 --- a/source/WebApp/.storybook/preview.js +++ /dev/null @@ -1,11 +0,0 @@ -import '../less/app.less'; - -export const parameters = { - actions: { argTypesRegex: "^on[A-Z].*" }, - controls: { - matchers: { - color: /(background|color)$/i, - date: /Date$/, - }, - }, -} \ No newline at end of file diff --git a/source/WebApp/.storybook/preview.tsx b/source/WebApp/.storybook/preview.tsx new file mode 100644 index 000000000..78ff086fe --- /dev/null +++ b/source/WebApp/.storybook/preview.tsx @@ -0,0 +1,30 @@ +import { DecoratorFn } from '@storybook/react'; +import React from 'react'; +import { RecoilRoot } from 'recoil'; +import { ViewportParameters } from '../app/shared/helpers/testing/viewportParameters'; +import '../less/app.less'; + +export const loaders = [ + () => document.fonts.ready +]; + +export const decorators: DecoratorFn[] = [ + (Story, props) => { + // https://github.com/storybookjs/test-runner/issues/97#issuecomment-1134419035 + (window as unknown as { STORY_VIEWPORT_PARAMETERS: ViewportParameters }).STORY_VIEWPORT_PARAMETERS = props?.parameters?.viewport; + return ; + }, + (Story) => + + +]; + +export const parameters = { + actions: { argTypesRegex: "^on[A-Z].*" }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, +} \ No newline at end of file diff --git a/source/WebApp/.storybook/test-runner.js b/source/WebApp/.storybook/test-runner.js new file mode 100644 index 000000000..7a9bc45cd --- /dev/null +++ b/source/WebApp/.storybook/test-runner.js @@ -0,0 +1,33 @@ +const { toMatchImageSnapshot } = require('jest-image-snapshot'); + +/** @type {import('@storybook/test-runner').TestRunnerConfig} */ +const config = { + setup() { + expect.extend({ toMatchImageSnapshot }); + }, + + async postRender(page, { title, name }) { + // https://github.com/storybookjs/test-runner/issues/97#issuecomment-1134419035 + const viewportParameters = await page.evaluate("window.STORY_VIEWPORT_PARAMETERS"); + if (viewportParameters) { + const viewport = viewportParameters.viewports[viewportParameters.defaultViewport]; + await page.setViewportSize({ + width: parseInt(viewport.styles.width, 10), + height: parseInt(viewport.styles.height, 10) + }); + } + + const image = await page.screenshot({ animations: 'disabled' }); + + const storyPathParts = title.split('/'); + const storyFileName = storyPathParts.pop(); + const storyDir = `${__dirname}/../app/${storyPathParts.join('/')}`; + + expect(image).toMatchImageSnapshot({ + customSnapshotsDir: `${storyDir}/__snapshots__/${storyFileName}`, + customSnapshotIdentifier: name + }); + } +}; + +module.exports = config; \ No newline at end of file diff --git a/source/WebApp/.vscode/settings.json b/source/WebApp/.vscode/settings.json index c8175b086..0b0e09848 100644 --- a/source/WebApp/.vscode/settings.json +++ b/source/WebApp/.vscode/settings.json @@ -8,6 +8,7 @@ "azcliversion", "azurewebsites", "Basepath", + "beforefieldinit", "boxable", "brfalse", "brinst", @@ -28,6 +29,7 @@ "cpblk", "cpobj", "creds", + "csso", "Csvg", "dagre", "debounced", @@ -46,6 +48,8 @@ "etype", "execa", "favicons", + "fontsource", + "formdata", "hacky", "Haverbeke", "headerless", @@ -87,6 +91,7 @@ "mixins", "mkrefany", "mllike", + "modespec", "montudor", "multiline", "multipipe", @@ -114,6 +119,7 @@ "refanyval", "requestfinished", "Robichaud", + "roboto", "rowspan", "scrollbar", "scroller", @@ -142,15 +148,15 @@ ], "eslint.lintTask.enable": true, "eslint.lintTask.options": ". --max-warnings 0 --ext .js,.ts", - "jest.pathToJest": "npm run test --", "search.exclude": { "/.git/": true, "/node_modules/": true, - "/public/": true + "/public/": true, + "/storybook-static/": true }, "typescript.tsdk": "./node_modules/typescript/lib", "editor.codeActionsOnSave": { - "source.fixAll": true + "source.fixAll": "explicit" }, "files.exclude": { "**/.git": true, diff --git a/source/WebApp/app/features/cm6-preview/CodeEditorSwitch.stories.tsx b/source/WebApp/app/features/cm6-preview/CodeEditorSwitch.stories.tsx index 7379bcc1a..f5d005c4c 100644 --- a/source/WebApp/app/features/cm6-preview/CodeEditorSwitch.stories.tsx +++ b/source/WebApp/app/features/cm6-preview/CodeEditorSwitch.stories.tsx @@ -1,7 +1,6 @@ import React from 'react'; -import { RecoilRoot } from 'recoil'; -import { DarkModeRoot } from '../../shared/testing/DarkModeRoot'; -import { recoilTestState } from '../../shared/helpers/testing/recoilTestState'; +import { TestSetRecoilState } from '../../shared/helpers/testing/TestSetRecoilState'; +import { darkModeStory } from '../../shared/testing/darkModeStory'; import { codeEditorPreviewEnabled } from './codeEditorPreviewEnabled'; import { CodeEditorSwitch } from './CodeEditorSwitch'; @@ -15,12 +14,12 @@ type TemplateProps = { const Template: React.FC = ({ preview } = {}) => <>

{/* needed for some styles to apply */}
- + - +
; export const Default = () =>