diff --git a/Example/Input/Authentication.ts b/Example/Input/Authentication.ts new file mode 100644 index 00000000..6d81c552 --- /dev/null +++ b/Example/Input/Authentication.ts @@ -0,0 +1,311 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IJSONSchema } from "../../../../base/common/jsonSchema.js"; +import { Disposable, IDisposable } from "../../../../base/common/lifecycle.js"; +import { isFalsyOrWhitespace } from "../../../../base/common/strings.js"; +import { localize } from "../../../../nls.js"; +import { + MenuId, + MenuRegistry, + registerAction2, +} from "../../../../platform/actions/common/actions.js"; +import { CommandsRegistry } from "../../../../platform/commands/common/commands.js"; +import { ContextKeyExpr } from "../../../../platform/contextkey/common/contextkey.js"; +import { IExtensionManifest } from "../../../../platform/extensions/common/extensions.js"; +import { SyncDescriptor } from "../../../../platform/instantiation/common/descriptors.js"; +import { Registry } from "../../../../platform/registry/common/platform.js"; +import { + IWorkbenchContribution, + registerWorkbenchContribution2, + WorkbenchPhase, +} from "../../../common/contributions.js"; +import { IAuthenticationUsageService } from "../../../services/authentication/browser/authenticationUsageService.js"; +import { + AuthenticationProviderInformation, + IAuthenticationService, +} from "../../../services/authentication/common/authentication.js"; +import { IBrowserWorkbenchEnvironmentService } from "../../../services/environment/browser/environmentService.js"; +import { + Extensions, + IExtensionFeaturesRegistry, + IExtensionFeatureTableRenderer, + IRenderedData, + IRowData, + ITableData, +} from "../../../services/extensionManagement/common/extensionFeatures.js"; +import { ExtensionsRegistry } from "../../../services/extensions/common/extensionsRegistry.js"; +import { ManageAccountPreferencesForExtensionAction } from "./actions/manageAccountPreferencesForExtensionAction.js"; +import { ManageTrustedExtensionsForAccountAction } from "./actions/manageTrustedExtensionsForAccountAction.js"; +import { SignOutOfAccountAction } from "./actions/signOutOfAccountAction.js"; + +const codeExchangeProxyCommand = CommandsRegistry.registerCommand( + "workbench.getCodeExchangeProxyEndpoints", + function (accessor, _) { + const environmentService = accessor.get( + IBrowserWorkbenchEnvironmentService, + ); + return environmentService.options?.codeExchangeProxyEndpoints; + }, +); + +const authenticationDefinitionSchema: IJSONSchema = { + type: "object", + additionalProperties: false, + properties: { + id: { + type: "string", + description: localize( + "authentication.id", + "The id of the authentication provider.", + ), + }, + label: { + type: "string", + description: localize( + "authentication.label", + "The human readable name of the authentication provider.", + ), + }, + }, +}; + +const authenticationExtPoint = ExtensionsRegistry.registerExtensionPoint< + AuthenticationProviderInformation[] +>({ + extensionPoint: "authentication", + jsonSchema: { + description: localize( + { + key: "authenticationExtensionPoint", + comment: [`'Contributes' means adds here`], + }, + "Contributes authentication", + ), + type: "array", + items: authenticationDefinitionSchema, + }, + activationEventsGenerator: (authenticationProviders, result) => { + for (const authenticationProvider of authenticationProviders) { + if (authenticationProvider.id) { + result.push( + `onAuthenticationRequest:${authenticationProvider.id}`, + ); + } + } + }, +}); + +class AuthenticationDataRenderer + extends Disposable + implements IExtensionFeatureTableRenderer +{ + readonly type = "table"; + + shouldRender(manifest: IExtensionManifest): boolean { + return !!manifest.contributes?.authentication; + } + + render(manifest: IExtensionManifest): IRenderedData { + const authentication = manifest.contributes?.authentication || []; + if (!authentication.length) { + return { data: { headers: [], rows: [] }, dispose: () => {} }; + } + + const headers = [ + localize("authenticationlabel", "Label"), + localize("authenticationid", "ID"), + ]; + + const rows: IRowData[][] = authentication + .sort((a, b) => a.label.localeCompare(b.label)) + .map((auth) => { + return [auth.label, auth.id]; + }); + + return { + data: { + headers, + rows, + }, + dispose: () => {}, + }; + } +} + +const extensionFeature = Registry.as( + Extensions.ExtensionFeaturesRegistry, +).registerExtensionFeature({ + id: "authentication", + label: localize("authentication", "Authentication"), + access: { + canToggle: false, + }, + renderer: new SyncDescriptor(AuthenticationDataRenderer), +}); + +class AuthenticationContribution + extends Disposable + implements IWorkbenchContribution +{ + static ID = "workbench.contrib.authentication"; + + private _placeholderMenuItem: IDisposable | undefined = + MenuRegistry.appendMenuItem(MenuId.AccountsContext, { + command: { + id: "noAuthenticationProviders", + title: localize( + "authentication.Placeholder", + "No accounts requested yet...", + ), + precondition: ContextKeyExpr.false(), + }, + }); + + constructor( + @IAuthenticationService + private readonly _authenticationService: IAuthenticationService, + ) { + super(); + this._register(codeExchangeProxyCommand); + this._register(extensionFeature); + + // Clear the placeholder menu item if there are already providers registered. + if (_authenticationService.getProviderIds().length) { + this._clearPlaceholderMenuItem(); + } + this._registerHandlers(); + this._registerAuthenticationExtentionPointHandler(); + this._registerActions(); + } + + private _registerAuthenticationExtentionPointHandler(): void { + authenticationExtPoint.setHandler((extensions, { added, removed }) => { + added.forEach((point) => { + for (const provider of point.value) { + if (isFalsyOrWhitespace(provider.id)) { + point.collector.error( + localize( + "authentication.missingId", + "An authentication contribution must specify an id.", + ), + ); + continue; + } + + if (isFalsyOrWhitespace(provider.label)) { + point.collector.error( + localize( + "authentication.missingLabel", + "An authentication contribution must specify a label.", + ), + ); + continue; + } + + if ( + !this._authenticationService.declaredProviders.some( + (p) => p.id === provider.id, + ) + ) { + this._authenticationService.registerDeclaredAuthenticationProvider( + provider, + ); + } else { + point.collector.error( + localize( + "authentication.idConflict", + "This authentication id '{0}' has already been registered", + provider.id, + ), + ); + } + } + }); + + const removedExtPoints = removed.flatMap((r) => r.value); + removedExtPoints.forEach((point) => { + const provider = + this._authenticationService.declaredProviders.find( + (provider) => provider.id === point.id, + ); + if (provider) { + this._authenticationService.unregisterDeclaredAuthenticationProvider( + provider.id, + ); + } + }); + }); + } + + private _registerHandlers(): void { + this._register( + this._authenticationService.onDidRegisterAuthenticationProvider( + (_e) => { + this._clearPlaceholderMenuItem(); + }, + ), + ); + this._register( + this._authenticationService.onDidUnregisterAuthenticationProvider( + (_e) => { + if (!this._authenticationService.getProviderIds().length) { + this._placeholderMenuItem = MenuRegistry.appendMenuItem( + MenuId.AccountsContext, + { + command: { + id: "noAuthenticationProviders", + title: localize("loading", "Loading..."), + precondition: ContextKeyExpr.false(), + }, + }, + ); + } + }, + ), + ); + } + + private _registerActions(): void { + this._register(registerAction2(SignOutOfAccountAction)); + this._register( + registerAction2(ManageTrustedExtensionsForAccountAction), + ); + this._register( + registerAction2(ManageAccountPreferencesForExtensionAction), + ); + } + + private _clearPlaceholderMenuItem(): void { + this._placeholderMenuItem?.dispose(); + this._placeholderMenuItem = undefined; + } +} + +class AuthenticationUsageContribution implements IWorkbenchContribution { + static ID = "workbench.contrib.authenticationUsage"; + + constructor( + @IAuthenticationUsageService + private readonly _authenticationUsageService: IAuthenticationUsageService, + ) { + this._initializeExtensionUsageCache(); + } + + private async _initializeExtensionUsageCache() { + await this._authenticationUsageService.initializeExtensionUsageCache(); + } +} + +registerWorkbenchContribution2( + AuthenticationContribution.ID, + AuthenticationContribution, + WorkbenchPhase.AfterRestored, +); +registerWorkbenchContribution2( + AuthenticationUsageContribution.ID, + AuthenticationUsageContribution, + WorkbenchPhase.Eventually, +); diff --git a/Source/Function/Output/Transformer/Visit.ts b/Source/Function/Output/Transformer/Visit.ts index 67598192..8e373734 100644 --- a/Source/Function/Output/Transformer/Visit.ts +++ b/Source/Function/Output/Transformer/Visit.ts @@ -62,28 +62,7 @@ export const Fn = ((Usage, Initializer) => if (isIdentifier(Declaration.name)) { const Count = Usage.get(Declaration.name.text); - // Don't inline if used within an object literal, regardless of context - const isUsedInObjectLiteral = (() => { - let result = false; - let current: Node | undefined = Declaration; - while (current) { - if ( - ts.isObjectLiteralExpression(current.parent) - ) { - result = true; - break; - } - current = current.parent; - } - return result; - })(); - - return ( - !Count || - Count > 1 || - !Declaration.initializer || - isUsedInObjectLiteral - ); + return !Count || Count > 1 || !Declaration.initializer; } return true; diff --git a/Target/Function/Output/Transformer/Visit.js b/Target/Function/Output/Transformer/Visit.js index 1ffb8f44..9ac5e585 100644 --- a/Target/Function/Output/Transformer/Visit.js +++ b/Target/Function/Output/Transformer/Visit.js @@ -1 +1 @@ -const M=(E,_)=>(...[T])=>(...[y])=>{const U=(r,u=0)=>{let S=0;if(S++,S>=100)return console.warn("Warning: Maximum node visits (100) reached for single Eliminate call",{TypeNode:o.SyntaxKind[r.kind],Depth:u}),{Node:r,Use:!1};if(u>=100)return console.warn("Warning: Maximum recursive depth (100) reached in Eliminate function.",{TypeNode:o.SyntaxKind[r.kind],Position:r.pos,Text:r.getText?.()}),{Node:r,Use:!1};let x=!1,e=r;if(o.isEmptyStatement(e))return{Node:d.createNotEmittedStatement(e),Use:!0};if(o.isVariableStatement(e)){const n=e.declarationList.declarations,i=n.filter(t=>{if(m(t.name)){const a=E.get(t.name.text),l=(()=>{let s=!1,f=t;for(;f;){if(o.isObjectLiteralExpression(f.parent)){s=!0;break}f=f.parent}return s})();return!a||a>1||!t.initializer||l}return!0});if(i.length===0)return{Node:d.createEmptyStatement(),Use:!0};i.length!==n.length&&(e=d.updateVariableStatement(e,e.modifiers,d.createVariableDeclarationList(i,e.declarationList.flags)),x=!0)}if(m(e))try{const n=e.text,i=E.get(n),t=b(n,_);if(t&&i===1){const a=e.parent;return o.isPropertyAccessExpression(a)&&a.name===e?{Node:e,Use:!1}:m(t)?{Node:d.createIdentifier(t.text),Use:!0}:{Node:o.transform(t,[l=>s=>s]).transformed[0],Use:!0}}}catch(n){console.error("Error during identifier replacement:",n)}const{Node:V,Use:g}=(n=>{let i=!1,t=!1;return{Node:o.visitEachChild(n,l=>{if(t)return l;const s=U(l,u+1);return s.Use===!1&&u>100?(t=!0,l):(i=i||s.Use,s.Node)},T),Use:i}})(e);return{Node:V,Use:x||g}};let c=y,I=!0;const p=100;let N=0;for(;I&&N=p){console.warn(`Warning: Maximum iteration count (${p}) reached. Possible infinite loop detected.`,{TypeNode:o.SyntaxKind[c.kind],Position:c.pos,Depth:"root"});break}const r=U(c);r.Use||(I=!1),c=r.Node,N++}return c},{default:o,isIdentifier:m,factory:d}=await import("typescript"),{default:b}=await import("../../Output/Visit/Get.js");var A=M;export{M as Fn,b as Get,A as default,d as factory,m as isIdentifier,o as ts}; +const g=(p,_)=>(...[x])=>(...[T])=>{const E=(r,l=0)=>{let I=0;if(I++,I>=100)return console.warn("Warning: Maximum node visits (100) reached for single Eliminate call",{TypeNode:o.SyntaxKind[r.kind],Depth:l}),{Node:r,Use:!1};if(l>=100)return console.warn("Warning: Maximum recursive depth (100) reached in Eliminate function.",{TypeNode:o.SyntaxKind[r.kind],Position:r.pos,Text:r.getText?.()}),{Node:r,Use:!1};let S=!1,e=r;if(o.isEmptyStatement(e))return{Node:d.createNotEmittedStatement(e),Use:!0};if(o.isVariableStatement(e)){const n=e.declarationList.declarations,i=n.filter(t=>{if(N(t.name)){const s=p.get(t.name.text);return!s||s>1||!t.initializer}return!0});if(i.length===0)return{Node:d.createEmptyStatement(),Use:!0};i.length!==n.length&&(e=d.updateVariableStatement(e,e.modifiers,d.createVariableDeclarationList(i,e.declarationList.flags)),S=!0)}if(N(e))try{const n=e.text,i=p.get(n),t=M(n,_);if(t&&i===1){const s=e.parent;return o.isPropertyAccessExpression(s)&&s.name===e?{Node:e,Use:!1}:N(t)?{Node:d.createIdentifier(t.text),Use:!0}:{Node:o.transform(t,[f=>c=>c]).transformed[0],Use:!0}}}catch(n){console.error("Error during identifier replacement:",n)}const{Node:y,Use:V}=(n=>{let i=!1,t=!1;return{Node:o.visitEachChild(n,f=>{if(t)return f;const c=E(f,l+1);return c.Use===!1&&l>100?(t=!0,f):(i=i||c.Use,c.Node)},x),Use:i}})(e);return{Node:y,Use:S||V}};let a=T,U=!0;const u=100;let m=0;for(;U&&m=u){console.warn(`Warning: Maximum iteration count (${u}) reached. Possible infinite loop detected.`,{TypeNode:o.SyntaxKind[a.kind],Position:a.pos,Depth:"root"});break}const r=E(a);r.Use||(U=!1),a=r.Node,m++}return a},{default:o,isIdentifier:N,factory:d}=await import("typescript"),{default:M}=await import("../../Output/Visit/Get.js");var h=g;export{g as Fn,M as Get,h as default,d as factory,N as isIdentifier,o as ts};