web: Make `SourceAPI` a singleton

As a first step towards a simpler Web API, convert `SourceAPI` from
a class to a constant object, under the assumption that `SourceAPI`
isn't a public Ruffle API and as such is safe to be changed.

As a result the different `ruffle-core` users don't need to construct
a new `SourceAPI` instance before calling `PublicAPI.negotiate()`.
This commit is contained in:
relrelb 2022-06-03 21:50:51 +03:00 committed by Mike Welsh
parent 8d30833d02
commit 1accf2d8f9
7 changed files with 26 additions and 61 deletions

View File

@ -9,7 +9,6 @@ export * from "./ruffle-imports";
export * from "./ruffle-object"; export * from "./ruffle-object";
export * from "./ruffle-player"; export * from "./ruffle-player";
export * from "./shadow-template"; export * from "./shadow-template";
export * from "./source-api";
export * from "./version"; export * from "./version";
export * from "./version-range"; export * from "./version-range";
export * from "./config"; export * from "./config";

View File

@ -32,7 +32,7 @@ export class PublicAPI {
*/ */
config: Config; config: Config;
private sources: Record<string, SourceAPI>; private sources: Record<string, typeof SourceAPI>;
private invoked: boolean; private invoked: boolean;
private newestName: string | null; private newestName: string | null;
private conflict: Record<string, unknown> | null; private conflict: Record<string, unknown> | null;
@ -111,11 +111,9 @@ export class PublicAPI {
* Register a given source with the Ruffle Public API. * Register a given source with the Ruffle Public API.
* *
* @param name The name of the source. * @param name The name of the source.
* @param api The public API object. This must conform to the shape
* of `SourceAPI`.
*/ */
registerSource(name: string, api: SourceAPI): void { registerSource(name: string): void {
this.sources[name] = api; this.sources[name] = SourceAPI;
} }
/** /**
@ -172,7 +170,7 @@ export class PublicAPI {
* *
* @returns An instance of the Source API. * @returns An instance of the Source API.
*/ */
newest(): SourceAPI | null { newest(): typeof SourceAPI | null {
const name = this.newestSourceName(); const name = this.newestSourceName();
return name !== null ? this.sources[name] : null; return name !== null ? this.sources[name] : null;
} }
@ -186,7 +184,7 @@ export class PublicAPI {
* @returns An instance of the Source API, if one or more * @returns An instance of the Source API, if one or more
* sources satisfied the requirement. * sources satisfied the requirement.
*/ */
satisfying(ver_requirement: string): SourceAPI | null { satisfying(ver_requirement: string): typeof SourceAPI | null {
const requirement = VersionRange.fromRequirementString(ver_requirement); const requirement = VersionRange.fromRequirementString(ver_requirement);
let valid = null; let valid = null;
@ -209,7 +207,7 @@ export class PublicAPI {
* *
* @returns An instance of the Source API * @returns An instance of the Source API
*/ */
localCompatible(): SourceAPI | null { localCompatible(): typeof SourceAPI | null {
if (this.sources.local !== undefined) { if (this.sources.local !== undefined) {
return this.satisfying("^" + this.sources.local.version); return this.satisfying("^" + this.sources.local.version);
} else { } else {
@ -223,7 +221,7 @@ export class PublicAPI {
* *
* @returns An instance of the Source API * @returns An instance of the Source API
*/ */
local(): SourceAPI | null { local(): typeof SourceAPI | null {
if (this.sources.local !== undefined) { if (this.sources.local !== undefined) {
return this.satisfying("=" + this.sources.local.version); return this.satisfying("=" + this.sources.local.version);
} else { } else {
@ -263,7 +261,6 @@ export class PublicAPI {
* version of Ruffle, since there is no Public API to upgrade from. * version of Ruffle, since there is no Public API to upgrade from.
* @param sourceName The name of this particular * @param sourceName The name of this particular
* Ruffle source. * Ruffle source.
* @param sourceAPI The Ruffle source to add.
* *
* If both parameters are provided they will be used to define a new Ruffle * If both parameters are provided they will be used to define a new Ruffle
* source to register with the public API. * source to register with the public API.
@ -271,8 +268,7 @@ export class PublicAPI {
*/ */
static negotiate( static negotiate(
prevRuffle: PublicAPI | null | Record<string, unknown>, prevRuffle: PublicAPI | null | Record<string, unknown>,
sourceName: string | undefined, sourceName: string | undefined
sourceAPI: SourceAPI | undefined
): PublicAPI { ): PublicAPI {
let publicAPI: PublicAPI; let publicAPI: PublicAPI;
if (prevRuffle instanceof PublicAPI) { if (prevRuffle instanceof PublicAPI) {
@ -281,8 +277,8 @@ export class PublicAPI {
publicAPI = new PublicAPI(prevRuffle); publicAPI = new PublicAPI(prevRuffle);
} }
if (sourceName !== undefined && sourceAPI !== undefined) { if (sourceName !== undefined) {
publicAPI.registerSource(sourceName, sourceAPI); publicAPI.registerSource(sourceName);
// Install the faux plugin detection immediately. // Install the faux plugin detection immediately.
// This is necessary because scripts such as SWFObject check for the // This is necessary because scripts such as SWFObject check for the
@ -290,7 +286,7 @@ export class PublicAPI {
// TODO: Maybe there's a better place for this. // TODO: Maybe there's a better place for this.
const polyfills = publicAPI.config.polyfills; const polyfills = publicAPI.config.polyfills;
if (polyfills !== false) { if (polyfills !== false) {
sourceAPI.pluginPolyfill(); SourceAPI.pluginPolyfill();
} }
} }

View File

@ -10,28 +10,11 @@ import { RufflePlayer } from "./ruffle-player";
* negotiator (see [[PublicAPI]]) what this particular version of Ruffle is and * negotiator (see [[PublicAPI]]) what this particular version of Ruffle is and
* how to control it. * how to control it.
*/ */
export class SourceAPI { export const SourceAPI = {
private name: string;
/** /**
* Construct a Source API. * The version of this particular API, as a string in a semver compatible format.
*
* @param name The name of this particular source.
*/ */
constructor(name: string) { version: "%VERSION_NUMBER%",
this.name = name;
}
/**
* The version of this particular API.
*
* This is returned as a string in a semver compatible format.
*
* @returns The version of this Ruffle source
*/
get version(): string {
return "%VERSION_NUMBER%";
}
/** /**
* Start up the polyfills. * Start up the polyfills.
@ -42,7 +25,7 @@ export class SourceAPI {
*/ */
polyfill(isExt: boolean): void { polyfill(isExt: boolean): void {
polyfill(isExt); polyfill(isExt);
} },
/** /**
* Polyfill the plugin detection. * Polyfill the plugin detection.
@ -51,7 +34,7 @@ export class SourceAPI {
*/ */
pluginPolyfill(): void { pluginPolyfill(): void {
pluginPolyfill(); pluginPolyfill();
} },
/** /**
* Create a Ruffle player element using this particular version of Ruffle. * Create a Ruffle player element using this particular version of Ruffle.
@ -62,5 +45,5 @@ export class SourceAPI {
createPlayer(): RufflePlayer { createPlayer(): RufflePlayer {
const name = registerElement("ruffle-player", RufflePlayer); const name = registerElement("ruffle-player", RufflePlayer);
return <RufflePlayer>document.createElement(name); return <RufflePlayer>document.createElement(name);
} },
} };

View File

@ -1,12 +1,8 @@
import "./index.css"; import "./index.css";
import { SourceAPI, PublicAPI } from "ruffle-core"; import { PublicAPI } from "ruffle-core";
window.RufflePlayer = PublicAPI.negotiate( window.RufflePlayer = PublicAPI.negotiate(window.RufflePlayer, "local");
window.RufflePlayer,
"local",
new SourceAPI("local")
);
const ruffle = window.RufflePlayer.newest(); const ruffle = window.RufflePlayer.newest();
let player; let player;

View File

@ -1,11 +1,7 @@
import * as utils from "./utils"; import * as utils from "./utils";
import { PublicAPI, SourceAPI, Letterbox } from "ruffle-core"; import { PublicAPI, Letterbox } from "ruffle-core";
const api = PublicAPI.negotiate( const api = PublicAPI.negotiate(window.RufflePlayer!, "local");
window.RufflePlayer!,
"local",
new SourceAPI("local")
);
window.RufflePlayer = api; window.RufflePlayer = api;
const ruffle = api.newest()!; const ruffle = api.newest()!;

View File

@ -1,4 +1,4 @@
import { PublicAPI, SourceAPI, Config } from "ruffle-core"; import { PublicAPI, Config } from "ruffle-core";
interface LoadMessage { interface LoadMessage {
type: "load"; type: "load";
@ -21,8 +21,7 @@ function handleMessage(message: Message) {
}; };
window.RufflePlayer = PublicAPI.negotiate( window.RufflePlayer = PublicAPI.negotiate(
window.RufflePlayer!, window.RufflePlayer!,
"extension", "extension"
new SourceAPI("extension")
); );
return {}; return {};
case "ping": case "ping":

View File

@ -1,7 +1,3 @@
import { PublicAPI, SourceAPI } from "ruffle-core"; import { PublicAPI } from "ruffle-core";
window.RufflePlayer = PublicAPI.negotiate( window.RufflePlayer = PublicAPI.negotiate(window.RufflePlayer, "local");
window.RufflePlayer,
"local",
new SourceAPI("local")
);