2021-06-29 05:27:27 +02:00
// SPDX-License-Identifier: MIT
2022-02-08 21:30:25 +01:00
// Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro
'use strict' ;
2021-06-29 05:27:27 +02:00
// A shim for the libWrapper library
export let libWrapper = undefined ;
2022-02-08 21:30:25 +01:00
export const VERSIONS = [ 1 , 12 , 1 ] ;
export const TGT _SPLIT _RE = new RegExp ( '([^.[]+|\\[(\'([^\'\\\\]|\\\\.)+?\'|"([^"\\\\]|\\\\.)+?")\\])' , 'g' ) ;
export const TGT _CLEANUP _RE = new RegExp ( '(^\\[\'|\'\\]$|^\\["|"\\]$)' , 'g' ) ;
// Main shim code
2021-06-29 05:27:27 +02:00
Hooks . once ( 'init' , ( ) => {
// Check if the real module is already loaded - if so, use it
if ( globalThis . libWrapper && ! ( globalThis . libWrapper . is _fallback ? ? true ) ) {
libWrapper = globalThis . libWrapper ;
return ;
}
// Fallback implementation
libWrapper = class {
static get is _fallback ( ) {
return true ;
}
2022-02-08 21:30:25 +01:00
static get WRAPPER ( ) {
return 'WRAPPER' ;
}
static get MIXED ( ) {
return 'MIXED' ;
}
static get OVERRIDE ( ) {
return 'OVERRIDE' ;
}
static register ( package _id , target , fn , type = 'MIXED' , { chain = undefined , bind = [ ] } = { } ) {
2021-06-29 05:27:27 +02:00
const is _setter = target . endsWith ( '#set' ) ;
target = ! is _setter ? target : target . slice ( 0 , - 4 ) ;
2022-02-08 21:30:25 +01:00
const split = target . match ( TGT _SPLIT _RE ) . map ( ( x ) => x . replace ( /\\(.)/g , '$1' ) . replace ( TGT _CLEANUP _RE , '' ) ) ;
2021-06-29 05:27:27 +02:00
const root _nm = split . splice ( 0 , 1 ) [ 0 ] ;
2022-02-08 21:30:25 +01:00
let obj , fn _name ;
if ( split . length == 0 ) {
obj = globalThis ;
fn _name = root _nm ;
} else {
const _eval = eval ;
fn _name = split . pop ( ) ;
obj = split . reduce ( ( x , y ) => x [ y ] , globalThis [ root _nm ] ? ? _eval ( root _nm ) ) ;
}
2021-06-29 05:27:27 +02:00
let iObj = obj ;
let descriptor = null ;
while ( iObj ) {
descriptor = Object . getOwnPropertyDescriptor ( iObj , fn _name ) ;
if ( descriptor ) break ;
iObj = Object . getPrototypeOf ( iObj ) ;
}
if ( ! descriptor || descriptor ? . configurable === false )
2022-02-08 21:30:25 +01:00
throw new Error (
` libWrapper Shim: ' ${ target } ' does not exist, could not be found, or has a non-configurable descriptor. ` ,
) ;
2021-06-29 05:27:27 +02:00
let original = null ;
const wrapper =
2022-02-08 21:30:25 +01:00
chain ? ? ( type . toUpperCase ? . ( ) != 'OVERRIDE' && type != 3 )
? function ( ... args ) {
return fn . call ( this , original . bind ( this ) , ... bind , ... args ) ;
2021-06-29 05:27:27 +02:00
}
2022-02-08 21:30:25 +01:00
: function ( ... args ) {
return fn . call ( this , ... bind , ... args ) ;
2021-06-29 05:27:27 +02:00
} ;
if ( ! is _setter ) {
if ( descriptor . value ) {
original = descriptor . value ;
descriptor . value = wrapper ;
} else {
original = descriptor . get ;
descriptor . get = wrapper ;
}
} else {
2022-02-08 21:30:25 +01:00
if ( ! descriptor . set ) throw new Error ( ` libWrapper Shim: ' ${ target } ' does not have a setter ` ) ;
2021-06-29 05:27:27 +02:00
original = descriptor . set ;
descriptor . set = wrapper ;
}
descriptor . configurable = true ;
Object . defineProperty ( obj , fn _name , descriptor ) ;
}
} ;
//************** USER CUSTOMIZABLE:
2022-02-08 21:30:25 +01:00
// Set up the ready hook that shows the "libWrapper not installed" warning dialog. Remove if undesired.
{
2021-06-29 05:27:27 +02:00
//************** USER CUSTOMIZABLE:
// Package ID & Package Title - by default attempts to auto-detect, but you might want to hardcode your package ID and title here to avoid potential auto-detect issues
const [ PACKAGE _ID , PACKAGE _TITLE ] = ( ( ) => {
const match = ( import . meta ? . url ? ? Error ( ) . stack ) ? . match ( /\/(worlds|systems|modules)\/(.+)(?=\/)/i ) ;
if ( match ? . length !== 3 ) return [ null , null ] ;
const dirs = match [ 2 ] . split ( '/' ) ;
if ( match [ 1 ] === 'worlds' )
return dirs . find ( ( n ) => n && game . world . id === n ) ? [ game . world . id , game . world . title ] : [ null , null ] ;
if ( match [ 1 ] === 'systems' )
return dirs . find ( ( n ) => n && game . system . id === n ) ? [ game . system . id , game . system . data . title ] : [ null , null ] ;
const id = dirs . find ( ( n ) => n && game . modules . has ( n ) ) ;
return [ id , game . modules . get ( id ) ? . data ? . title ] ;
} ) ( ) ;
if ( ! PACKAGE _ID || ! PACKAGE _TITLE ) {
console . error (
'libWrapper Shim: Could not auto-detect package ID and/or title. The libWrapper fallback warning dialog will be disabled.' ,
) ;
return ;
}
Hooks . once ( 'ready' , ( ) => {
//************** USER CUSTOMIZABLE:
// Title and message for the dialog shown when the real libWrapper is not installed.
const FALLBACK _MESSAGE _TITLE = PACKAGE _TITLE ;
const FALLBACK _MESSAGE = `
< p > < b > '${PACKAGE_TITLE}' depends on the 'libWrapper' module , which is not present . < / b > < / p >
< p > A fallback implementation will be used , which increases the chance of compatibility issues with other modules . < / p >
< small > < p > 'libWrapper' is a library which provides package developers with a simple way to modify core Foundry VTT code , while reducing the likelihood of conflict with other packages . < / p >
< p > You can install it from the "Add-on Modules" tab in the < a href = "javascript:game.shutDown()" > Foundry VTT Setup < /a>, from the <a href="https:/ / foundryvtt . com / packages / lib - wrapper ">Foundry VTT package repository</a>, or from <a href=" https : //github.com/ruipin/fvtt-lib-wrapper/">libWrapper's Github page</a>.</p></small>
` ;
// Settings key used for the "Don't remind me again" setting
const DONT _REMIND _AGAIN _KEY = 'libwrapper-dont-remind-again' ;
// Dialog code
console . warn ( ` ${ PACKAGE _TITLE } : libWrapper not present, using fallback implementation. ` ) ;
game . settings . register ( PACKAGE _ID , DONT _REMIND _AGAIN _KEY , {
name : '' ,
default : false ,
type : Boolean ,
scope : 'world' ,
config : false ,
} ) ;
if ( game . user . isGM && ! game . settings . get ( PACKAGE _ID , DONT _REMIND _AGAIN _KEY ) ) {
new Dialog ( {
title : FALLBACK _MESSAGE _TITLE ,
content : FALLBACK _MESSAGE ,
buttons : {
ok : { icon : '<i class="fas fa-check"></i>' , label : 'Understood' } ,
dont _remind : {
icon : '<i class="fas fa-times"></i>' ,
label : "Don't remind me again" ,
callback : ( ) => game . settings . set ( PACKAGE _ID , DONT _REMIND _AGAIN _KEY , true ) ,
} ,
} ,
} ) . render ( true ) ;
}
} ) ;
}
} ) ;