var _ _create = Object . create ;
var _ _defProp = Object . defineProperty ;
var _ _getOwnPropDesc = Object . getOwnPropertyDescriptor ;
var _ _getOwnPropNames = Object . getOwnPropertyNames ;
var _ _getProtoOf = Object . getPrototypeOf ;
var _ _hasOwnProp = Object . prototype . hasOwnProperty ;
var _ _commonJS = ( cb , mod ) => function _ _require ( ) {
return mod || ( 0 , cb [ _ _getOwnPropNames ( cb ) [ 0 ] ] ) ( ( mod = { exports : { } } ) . exports , mod ) , mod . exports ;
} ;
var _ _export = ( target , all ) => {
for ( var name in all )
_ _defProp ( target , name , { get : all [ name ] , enumerable : true } ) ;
} ;
var _ _copyProps = ( to , from , except , desc ) => {
if ( from && typeof from === "object" || typeof from === "function" ) {
for ( let key of _ _getOwnPropNames ( from ) )
if ( ! _ _hasOwnProp . call ( to , key ) && key !== except )
_ _defProp ( to , key , { get : ( ) => from [ key ] , enumerable : ! ( desc = _ _getOwnPropDesc ( from , key ) ) || desc . enumerable } ) ;
}
return to ;
} ;
var _ _toESM = ( mod , isNodeMode , target ) => ( target = mod != null ? _ _create ( _ _getProtoOf ( mod ) ) : { } , _ _copyProps (
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || ! mod || ! mod . _ _esModule ? _ _defProp ( target , "default" , { value : mod , enumerable : true } ) : target ,
mod
) ) ;
var _ _toCommonJS = ( mod ) => _ _copyProps ( _ _defProp ( { } , "__esModule" , { value : true } ) , mod ) ;
// node_modules/obsidian-daily-notes-interface/dist/main.js
var require _main = _ _commonJS ( {
"node_modules/obsidian-daily-notes-interface/dist/main.js" ( exports ) {
"use strict" ;
Object . defineProperty ( exports , "__esModule" , { value : true } ) ;
var obsidian = require ( "obsidian" ) ;
var DEFAULT _DAILY _NOTE _FORMAT = "YYYY-MM-DD" ;
var DEFAULT _WEEKLY _NOTE _FORMAT = "gggg-[W]ww" ;
var DEFAULT _MONTHLY _NOTE _FORMAT = "YYYY-MM" ;
var DEFAULT _QUARTERLY _NOTE _FORMAT = "YYYY-[Q]Q" ;
var DEFAULT _YEARLY _NOTE _FORMAT = "YYYY" ;
function shouldUsePeriodicNotesSettings ( periodicity ) {
var _a , _b ;
const periodicNotes = window . app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a [ periodicity ] ) == null ? void 0 : _b . enabled ) ;
}
function getDailyNoteSettings2 ( ) {
var _a , _b , _c , _d ;
try {
const { internalPlugins , plugins } = window . app ;
if ( shouldUsePeriodicNotesSettings ( "daily" ) ) {
const { format : format2 , folder : folder2 , template : template2 } = ( ( _b = ( _a = plugins . getPlugin ( "periodic-notes" ) ) == null ? void 0 : _a . settings ) == null ? void 0 : _b . daily ) || { } ;
return {
format : format2 || DEFAULT _DAILY _NOTE _FORMAT ,
folder : ( folder2 == null ? void 0 : folder2 . trim ( ) ) || "" ,
template : ( template2 == null ? void 0 : template2 . trim ( ) ) || ""
} ;
}
const { folder , format , template } = ( ( _d = ( _c = internalPlugins . getPluginById ( "daily-notes" ) ) == null ? void 0 : _c . instance ) == null ? void 0 : _d . options ) || { } ;
return {
format : format || DEFAULT _DAILY _NOTE _FORMAT ,
folder : ( folder == null ? void 0 : folder . trim ( ) ) || "" ,
template : ( template == null ? void 0 : template . trim ( ) ) || ""
} ;
} catch ( err ) {
console . info ( "No custom daily note settings found!" , err ) ;
}
}
function getWeeklyNoteSettings ( ) {
var _a , _b , _c , _d , _e , _f , _g ;
try {
const pluginManager = window . app . plugins ;
const calendarSettings = ( _a = pluginManager . getPlugin ( "calendar" ) ) == null ? void 0 : _a . options ;
const periodicNotesSettings = ( _c = ( _b = pluginManager . getPlugin ( "periodic-notes" ) ) == null ? void 0 : _b . settings ) == null ? void 0 : _c . weekly ;
if ( shouldUsePeriodicNotesSettings ( "weekly" ) ) {
return {
format : periodicNotesSettings . format || DEFAULT _WEEKLY _NOTE _FORMAT ,
folder : ( ( _d = periodicNotesSettings . folder ) == null ? void 0 : _d . trim ( ) ) || "" ,
template : ( ( _e = periodicNotesSettings . template ) == null ? void 0 : _e . trim ( ) ) || ""
} ;
}
const settings = calendarSettings || { } ;
return {
format : settings . weeklyNoteFormat || DEFAULT _WEEKLY _NOTE _FORMAT ,
folder : ( ( _f = settings . weeklyNoteFolder ) == null ? void 0 : _f . trim ( ) ) || "" ,
template : ( ( _g = settings . weeklyNoteTemplate ) == null ? void 0 : _g . trim ( ) ) || ""
} ;
} catch ( err ) {
console . info ( "No custom weekly note settings found!" , err ) ;
}
}
function getMonthlyNoteSettings ( ) {
var _a , _b , _c , _d ;
const pluginManager = window . app . plugins ;
try {
const settings = shouldUsePeriodicNotesSettings ( "monthly" ) && ( ( _b = ( _a = pluginManager . getPlugin ( "periodic-notes" ) ) == null ? void 0 : _a . settings ) == null ? void 0 : _b . monthly ) || { } ;
return {
format : settings . format || DEFAULT _MONTHLY _NOTE _FORMAT ,
folder : ( ( _c = settings . folder ) == null ? void 0 : _c . trim ( ) ) || "" ,
template : ( ( _d = settings . template ) == null ? void 0 : _d . trim ( ) ) || ""
} ;
} catch ( err ) {
console . info ( "No custom monthly note settings found!" , err ) ;
}
}
function getQuarterlyNoteSettings ( ) {
var _a , _b , _c , _d ;
const pluginManager = window . app . plugins ;
try {
const settings = shouldUsePeriodicNotesSettings ( "quarterly" ) && ( ( _b = ( _a = pluginManager . getPlugin ( "periodic-notes" ) ) == null ? void 0 : _a . settings ) == null ? void 0 : _b . quarterly ) || { } ;
return {
format : settings . format || DEFAULT _QUARTERLY _NOTE _FORMAT ,
folder : ( ( _c = settings . folder ) == null ? void 0 : _c . trim ( ) ) || "" ,
template : ( ( _d = settings . template ) == null ? void 0 : _d . trim ( ) ) || ""
} ;
} catch ( err ) {
console . info ( "No custom quarterly note settings found!" , err ) ;
}
}
function getYearlyNoteSettings ( ) {
var _a , _b , _c , _d ;
const pluginManager = window . app . plugins ;
try {
const settings = shouldUsePeriodicNotesSettings ( "yearly" ) && ( ( _b = ( _a = pluginManager . getPlugin ( "periodic-notes" ) ) == null ? void 0 : _a . settings ) == null ? void 0 : _b . yearly ) || { } ;
return {
format : settings . format || DEFAULT _YEARLY _NOTE _FORMAT ,
folder : ( ( _c = settings . folder ) == null ? void 0 : _c . trim ( ) ) || "" ,
template : ( ( _d = settings . template ) == null ? void 0 : _d . trim ( ) ) || ""
} ;
} catch ( err ) {
console . info ( "No custom yearly note settings found!" , err ) ;
}
}
function join ( ... partSegments ) {
let parts = [ ] ;
for ( let i = 0 , l = partSegments . length ; i < l ; i ++ ) {
parts = parts . concat ( partSegments [ i ] . split ( "/" ) ) ;
}
const newParts = [ ] ;
for ( let i = 0 , l = parts . length ; i < l ; i ++ ) {
const part = parts [ i ] ;
if ( ! part || part === "." )
continue ;
else
newParts . push ( part ) ;
}
if ( parts [ 0 ] === "" )
newParts . unshift ( "" ) ;
return newParts . join ( "/" ) ;
}
function basename ( fullPath ) {
let base = fullPath . substring ( fullPath . lastIndexOf ( "/" ) + 1 ) ;
if ( base . lastIndexOf ( "." ) != - 1 )
base = base . substring ( 0 , base . lastIndexOf ( "." ) ) ;
return base ;
}
async function ensureFolderExists ( path ) {
const dirs = path . replace ( /\\/g , "/" ) . split ( "/" ) ;
dirs . pop ( ) ;
if ( dirs . length ) {
const dir = join ( ... dirs ) ;
if ( ! window . app . vault . getAbstractFileByPath ( dir ) ) {
await window . app . vault . createFolder ( dir ) ;
}
}
}
async function getNotePath ( directory , filename ) {
if ( ! filename . endsWith ( ".md" ) ) {
filename += ".md" ;
}
const path = obsidian . normalizePath ( join ( directory , filename ) ) ;
await ensureFolderExists ( path ) ;
return path ;
}
async function getTemplateInfo ( template ) {
const { metadataCache , vault } = window . app ;
const templatePath = obsidian . normalizePath ( template ) ;
if ( templatePath === "/" ) {
return Promise . resolve ( [ "" , null ] ) ;
}
try {
const templateFile = metadataCache . getFirstLinkpathDest ( templatePath , "" ) ;
const contents = await vault . cachedRead ( templateFile ) ;
const IFoldInfo = window . app . foldManager . load ( templateFile ) ;
return [ contents , IFoldInfo ] ;
} catch ( err ) {
console . error ( ` Failed to read the daily note template ' ${ templatePath } ' ` , err ) ;
new obsidian . Notice ( "Failed to read the daily note template" ) ;
return [ "" , null ] ;
}
}
function getDateUID ( date , granularity = "day" ) {
const ts = date . clone ( ) . startOf ( granularity ) . format ( ) ;
return ` ${ granularity } - ${ ts } ` ;
}
function removeEscapedCharacters ( format ) {
return format . replace ( /\[[^\]]*\]/g , "" ) ;
}
function isFormatAmbiguous ( format , granularity ) {
if ( granularity === "week" ) {
const cleanFormat = removeEscapedCharacters ( format ) ;
return /w{1,2}/i . test ( cleanFormat ) && ( /M{1,4}/ . test ( cleanFormat ) || /D{1,4}/ . test ( cleanFormat ) ) ;
}
return false ;
}
function getDateFromFile ( file , granularity ) {
return getDateFromFilename ( file . basename , granularity ) ;
}
function getDateFromPath ( path , granularity ) {
return getDateFromFilename ( basename ( path ) , granularity ) ;
}
function getDateFromFilename ( filename , granularity ) {
const getSettings = {
day : getDailyNoteSettings2 ,
week : getWeeklyNoteSettings ,
month : getMonthlyNoteSettings ,
quarter : getQuarterlyNoteSettings ,
year : getYearlyNoteSettings
} ;
const format = getSettings [ granularity ] ( ) . format . split ( "/" ) . pop ( ) ;
const noteDate = window . moment ( filename , format , true ) ;
if ( ! noteDate . isValid ( ) ) {
return null ;
}
if ( isFormatAmbiguous ( format , granularity ) ) {
if ( granularity === "week" ) {
const cleanFormat = removeEscapedCharacters ( format ) ;
if ( /w{1,2}/i . test ( cleanFormat ) ) {
return window . moment (
filename ,
// If format contains week, remove day & month formatting
format . replace ( /M{1,4}/g , "" ) . replace ( /D{1,4}/g , "" ) ,
false
) ;
}
}
}
return noteDate ;
}
var DailyNotesFolderMissingError = class extends Error {
} ;
async function createDailyNote ( date ) {
const app = window . app ;
const { vault } = app ;
const moment2 = window . moment ;
const { template , format , folder } = getDailyNoteSettings2 ( ) ;
const [ templateContents , IFoldInfo ] = await getTemplateInfo ( template ) ;
const filename = date . format ( format ) ;
const normalizedPath = await getNotePath ( folder , filename ) ;
try {
const createdFile = await vault . create ( normalizedPath , templateContents . replace ( /{{\s*date\s*}}/gi , filename ) . replace ( /{{\s*time\s*}}/gi , moment2 ( ) . format ( "HH:mm" ) ) . replace ( /{{\s*title\s*}}/gi , filename ) . replace ( /{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi , ( _ , _timeOrDate , calc , timeDelta , unit , momentFormat ) => {
const now = moment2 ( ) ;
const currentDate = date . clone ( ) . set ( {
hour : now . get ( "hour" ) ,
minute : now . get ( "minute" ) ,
second : now . get ( "second" )
} ) ;
if ( calc ) {
currentDate . add ( parseInt ( timeDelta , 10 ) , unit ) ;
}
if ( momentFormat ) {
return currentDate . format ( momentFormat . substring ( 1 ) . trim ( ) ) ;
}
return currentDate . format ( format ) ;
} ) . replace ( /{{\s*yesterday\s*}}/gi , date . clone ( ) . subtract ( 1 , "day" ) . format ( format ) ) . replace ( /{{\s*tomorrow\s*}}/gi , date . clone ( ) . add ( 1 , "d" ) . format ( format ) ) ) ;
app . foldManager . save ( createdFile , IFoldInfo ) ;
return createdFile ;
} catch ( err ) {
console . error ( ` Failed to create file: ' ${ normalizedPath } ' ` , err ) ;
new obsidian . Notice ( "Unable to create new file." ) ;
}
}
function getDailyNote ( date , dailyNotes ) {
var _a ;
return ( _a = dailyNotes [ getDateUID ( date , "day" ) ] ) != null ? _a : null ;
}
function getAllDailyNotes ( ) {
const { vault } = window . app ;
const { folder } = getDailyNoteSettings2 ( ) ;
const dailyNotesFolder = vault . getAbstractFileByPath ( obsidian . normalizePath ( folder ) ) ;
if ( ! dailyNotesFolder ) {
throw new DailyNotesFolderMissingError ( "Failed to find daily notes folder" ) ;
}
const dailyNotes = { } ;
obsidian . Vault . recurseChildren ( dailyNotesFolder , ( note ) => {
if ( note instanceof obsidian . TFile ) {
const date = getDateFromFile ( note , "day" ) ;
if ( date ) {
const dateString = getDateUID ( date , "day" ) ;
dailyNotes [ dateString ] = note ;
}
}
} ) ;
return dailyNotes ;
}
var WeeklyNotesFolderMissingError = class extends Error {
} ;
function getDaysOfWeek ( ) {
const { moment : moment2 } = window ;
let weekStart = moment2 . localeData ( ) . _week . dow ;
const daysOfWeek = [
"sunday" ,
"monday" ,
"tuesday" ,
"wednesday" ,
"thursday" ,
"friday" ,
"saturday"
] ;
while ( weekStart ) {
daysOfWeek . push ( daysOfWeek . shift ( ) ) ;
weekStart -- ;
}
return daysOfWeek ;
}
function getDayOfWeekNumericalValue ( dayOfWeekName ) {
return getDaysOfWeek ( ) . indexOf ( dayOfWeekName . toLowerCase ( ) ) ;
}
async function createWeeklyNote ( date ) {
const { vault } = window . app ;
const { template , format , folder } = getWeeklyNoteSettings ( ) ;
const [ templateContents , IFoldInfo ] = await getTemplateInfo ( template ) ;
const filename = date . format ( format ) ;
const normalizedPath = await getNotePath ( folder , filename ) ;
try {
const createdFile = await vault . create ( normalizedPath , templateContents . replace ( /{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi , ( _ , _timeOrDate , calc , timeDelta , unit , momentFormat ) => {
const now = window . moment ( ) ;
const currentDate = date . clone ( ) . set ( {
hour : now . get ( "hour" ) ,
minute : now . get ( "minute" ) ,
second : now . get ( "second" )
} ) ;
if ( calc ) {
currentDate . add ( parseInt ( timeDelta , 10 ) , unit ) ;
}
if ( momentFormat ) {
return currentDate . format ( momentFormat . substring ( 1 ) . trim ( ) ) ;
}
return currentDate . format ( format ) ;
} ) . replace ( /{{\s*title\s*}}/gi , filename ) . replace ( /{{\s*time\s*}}/gi , window . moment ( ) . format ( "HH:mm" ) ) . replace ( /{{\s*(sunday|monday|tuesday|wednesday|thursday|friday|saturday)\s*:(.*?)}}/gi , ( _ , dayOfWeek , momentFormat ) => {
const day = getDayOfWeekNumericalValue ( dayOfWeek ) ;
return date . weekday ( day ) . format ( momentFormat . trim ( ) ) ;
} ) ) ;
window . app . foldManager . save ( createdFile , IFoldInfo ) ;
return createdFile ;
} catch ( err ) {
console . error ( ` Failed to create file: ' ${ normalizedPath } ' ` , err ) ;
new obsidian . Notice ( "Unable to create new file." ) ;
}
}
function getWeeklyNote ( date , weeklyNotes ) {
var _a ;
return ( _a = weeklyNotes [ getDateUID ( date , "week" ) ] ) != null ? _a : null ;
}
function getAllWeeklyNotes ( ) {
const weeklyNotes = { } ;
if ( ! appHasWeeklyNotesPluginLoaded ( ) ) {
return weeklyNotes ;
}
const { vault } = window . app ;
const { folder } = getWeeklyNoteSettings ( ) ;
const weeklyNotesFolder = vault . getAbstractFileByPath ( obsidian . normalizePath ( folder ) ) ;
if ( ! weeklyNotesFolder ) {
throw new WeeklyNotesFolderMissingError ( "Failed to find weekly notes folder" ) ;
}
obsidian . Vault . recurseChildren ( weeklyNotesFolder , ( note ) => {
if ( note instanceof obsidian . TFile ) {
const date = getDateFromFile ( note , "week" ) ;
if ( date ) {
const dateString = getDateUID ( date , "week" ) ;
weeklyNotes [ dateString ] = note ;
}
}
} ) ;
return weeklyNotes ;
}
var MonthlyNotesFolderMissingError = class extends Error {
} ;
async function createMonthlyNote ( date ) {
const { vault } = window . app ;
const { template , format , folder } = getMonthlyNoteSettings ( ) ;
const [ templateContents , IFoldInfo ] = await getTemplateInfo ( template ) ;
const filename = date . format ( format ) ;
const normalizedPath = await getNotePath ( folder , filename ) ;
try {
const createdFile = await vault . create ( normalizedPath , templateContents . replace ( /{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi , ( _ , _timeOrDate , calc , timeDelta , unit , momentFormat ) => {
const now = window . moment ( ) ;
const currentDate = date . clone ( ) . set ( {
hour : now . get ( "hour" ) ,
minute : now . get ( "minute" ) ,
second : now . get ( "second" )
} ) ;
if ( calc ) {
currentDate . add ( parseInt ( timeDelta , 10 ) , unit ) ;
}
if ( momentFormat ) {
return currentDate . format ( momentFormat . substring ( 1 ) . trim ( ) ) ;
}
return currentDate . format ( format ) ;
} ) . replace ( /{{\s*date\s*}}/gi , filename ) . replace ( /{{\s*time\s*}}/gi , window . moment ( ) . format ( "HH:mm" ) ) . replace ( /{{\s*title\s*}}/gi , filename ) ) ;
window . app . foldManager . save ( createdFile , IFoldInfo ) ;
return createdFile ;
} catch ( err ) {
console . error ( ` Failed to create file: ' ${ normalizedPath } ' ` , err ) ;
new obsidian . Notice ( "Unable to create new file." ) ;
}
}
function getMonthlyNote ( date , monthlyNotes ) {
var _a ;
return ( _a = monthlyNotes [ getDateUID ( date , "month" ) ] ) != null ? _a : null ;
}
function getAllMonthlyNotes ( ) {
const monthlyNotes = { } ;
if ( ! appHasMonthlyNotesPluginLoaded ( ) ) {
return monthlyNotes ;
}
const { vault } = window . app ;
const { folder } = getMonthlyNoteSettings ( ) ;
const monthlyNotesFolder = vault . getAbstractFileByPath ( obsidian . normalizePath ( folder ) ) ;
if ( ! monthlyNotesFolder ) {
throw new MonthlyNotesFolderMissingError ( "Failed to find monthly notes folder" ) ;
}
obsidian . Vault . recurseChildren ( monthlyNotesFolder , ( note ) => {
if ( note instanceof obsidian . TFile ) {
const date = getDateFromFile ( note , "month" ) ;
if ( date ) {
const dateString = getDateUID ( date , "month" ) ;
monthlyNotes [ dateString ] = note ;
}
}
} ) ;
return monthlyNotes ;
}
var QuarterlyNotesFolderMissingError = class extends Error {
} ;
async function createQuarterlyNote ( date ) {
const { vault } = window . app ;
const { template , format , folder } = getQuarterlyNoteSettings ( ) ;
const [ templateContents , IFoldInfo ] = await getTemplateInfo ( template ) ;
const filename = date . format ( format ) ;
const normalizedPath = await getNotePath ( folder , filename ) ;
try {
const createdFile = await vault . create ( normalizedPath , templateContents . replace ( /{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi , ( _ , _timeOrDate , calc , timeDelta , unit , momentFormat ) => {
const now = window . moment ( ) ;
const currentDate = date . clone ( ) . set ( {
hour : now . get ( "hour" ) ,
minute : now . get ( "minute" ) ,
second : now . get ( "second" )
} ) ;
if ( calc ) {
currentDate . add ( parseInt ( timeDelta , 10 ) , unit ) ;
}
if ( momentFormat ) {
return currentDate . format ( momentFormat . substring ( 1 ) . trim ( ) ) ;
}
return currentDate . format ( format ) ;
} ) . replace ( /{{\s*date\s*}}/gi , filename ) . replace ( /{{\s*time\s*}}/gi , window . moment ( ) . format ( "HH:mm" ) ) . replace ( /{{\s*title\s*}}/gi , filename ) ) ;
window . app . foldManager . save ( createdFile , IFoldInfo ) ;
return createdFile ;
} catch ( err ) {
console . error ( ` Failed to create file: ' ${ normalizedPath } ' ` , err ) ;
new obsidian . Notice ( "Unable to create new file." ) ;
}
}
function getQuarterlyNote ( date , quarterly ) {
var _a ;
return ( _a = quarterly [ getDateUID ( date , "quarter" ) ] ) != null ? _a : null ;
}
function getAllQuarterlyNotes ( ) {
const quarterly = { } ;
if ( ! appHasQuarterlyNotesPluginLoaded ( ) ) {
return quarterly ;
}
const { vault } = window . app ;
const { folder } = getQuarterlyNoteSettings ( ) ;
const quarterlyFolder = vault . getAbstractFileByPath ( obsidian . normalizePath ( folder ) ) ;
if ( ! quarterlyFolder ) {
throw new QuarterlyNotesFolderMissingError ( "Failed to find quarterly notes folder" ) ;
}
obsidian . Vault . recurseChildren ( quarterlyFolder , ( note ) => {
if ( note instanceof obsidian . TFile ) {
const date = getDateFromFile ( note , "quarter" ) ;
if ( date ) {
const dateString = getDateUID ( date , "quarter" ) ;
quarterly [ dateString ] = note ;
}
}
} ) ;
return quarterly ;
}
var YearlyNotesFolderMissingError = class extends Error {
} ;
async function createYearlyNote ( date ) {
const { vault } = window . app ;
const { template , format , folder } = getYearlyNoteSettings ( ) ;
const [ templateContents , IFoldInfo ] = await getTemplateInfo ( template ) ;
const filename = date . format ( format ) ;
const normalizedPath = await getNotePath ( folder , filename ) ;
try {
const createdFile = await vault . create ( normalizedPath , templateContents . replace ( /{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi , ( _ , _timeOrDate , calc , timeDelta , unit , momentFormat ) => {
const now = window . moment ( ) ;
const currentDate = date . clone ( ) . set ( {
hour : now . get ( "hour" ) ,
minute : now . get ( "minute" ) ,
second : now . get ( "second" )
} ) ;
if ( calc ) {
currentDate . add ( parseInt ( timeDelta , 10 ) , unit ) ;
}
if ( momentFormat ) {
return currentDate . format ( momentFormat . substring ( 1 ) . trim ( ) ) ;
}
return currentDate . format ( format ) ;
} ) . replace ( /{{\s*date\s*}}/gi , filename ) . replace ( /{{\s*time\s*}}/gi , window . moment ( ) . format ( "HH:mm" ) ) . replace ( /{{\s*title\s*}}/gi , filename ) ) ;
window . app . foldManager . save ( createdFile , IFoldInfo ) ;
return createdFile ;
} catch ( err ) {
console . error ( ` Failed to create file: ' ${ normalizedPath } ' ` , err ) ;
new obsidian . Notice ( "Unable to create new file." ) ;
}
}
function getYearlyNote ( date , yearlyNotes ) {
var _a ;
return ( _a = yearlyNotes [ getDateUID ( date , "year" ) ] ) != null ? _a : null ;
}
function getAllYearlyNotes ( ) {
const yearlyNotes = { } ;
if ( ! appHasYearlyNotesPluginLoaded ( ) ) {
return yearlyNotes ;
}
const { vault } = window . app ;
const { folder } = getYearlyNoteSettings ( ) ;
const yearlyNotesFolder = vault . getAbstractFileByPath ( obsidian . normalizePath ( folder ) ) ;
if ( ! yearlyNotesFolder ) {
throw new YearlyNotesFolderMissingError ( "Failed to find yearly notes folder" ) ;
}
obsidian . Vault . recurseChildren ( yearlyNotesFolder , ( note ) => {
if ( note instanceof obsidian . TFile ) {
const date = getDateFromFile ( note , "year" ) ;
if ( date ) {
const dateString = getDateUID ( date , "year" ) ;
yearlyNotes [ dateString ] = note ;
}
}
} ) ;
return yearlyNotes ;
}
function appHasDailyNotesPluginLoaded ( ) {
var _a , _b ;
const { app } = window ;
const dailyNotesPlugin = app . internalPlugins . plugins [ "daily-notes" ] ;
if ( dailyNotesPlugin && dailyNotesPlugin . enabled ) {
return true ;
}
const periodicNotes = app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a . daily ) == null ? void 0 : _b . enabled ) ;
}
function appHasWeeklyNotesPluginLoaded ( ) {
var _a , _b ;
const { app } = window ;
if ( app . plugins . getPlugin ( "calendar" ) ) {
return true ;
}
const periodicNotes = app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a . weekly ) == null ? void 0 : _b . enabled ) ;
}
function appHasMonthlyNotesPluginLoaded ( ) {
var _a , _b ;
const { app } = window ;
const periodicNotes = app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a . monthly ) == null ? void 0 : _b . enabled ) ;
}
function appHasQuarterlyNotesPluginLoaded ( ) {
var _a , _b ;
const { app } = window ;
const periodicNotes = app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a . quarterly ) == null ? void 0 : _b . enabled ) ;
}
function appHasYearlyNotesPluginLoaded ( ) {
var _a , _b ;
const { app } = window ;
const periodicNotes = app . plugins . getPlugin ( "periodic-notes" ) ;
return periodicNotes && ( ( _b = ( _a = periodicNotes . settings ) == null ? void 0 : _a . yearly ) == null ? void 0 : _b . enabled ) ;
}
function getPeriodicNoteSettings ( granularity ) {
const getSettings = {
day : getDailyNoteSettings2 ,
week : getWeeklyNoteSettings ,
month : getMonthlyNoteSettings ,
quarter : getQuarterlyNoteSettings ,
year : getYearlyNoteSettings
} [ granularity ] ;
return getSettings ( ) ;
}
function createPeriodicNote ( granularity , date ) {
const createFn = {
day : createDailyNote ,
month : createMonthlyNote ,
week : createWeeklyNote
} ;
return createFn [ granularity ] ( date ) ;
}
exports . DEFAULT _DAILY _NOTE _FORMAT = DEFAULT _DAILY _NOTE _FORMAT ;
exports . DEFAULT _MONTHLY _NOTE _FORMAT = DEFAULT _MONTHLY _NOTE _FORMAT ;
exports . DEFAULT _QUARTERLY _NOTE _FORMAT = DEFAULT _QUARTERLY _NOTE _FORMAT ;
exports . DEFAULT _WEEKLY _NOTE _FORMAT = DEFAULT _WEEKLY _NOTE _FORMAT ;
exports . DEFAULT _YEARLY _NOTE _FORMAT = DEFAULT _YEARLY _NOTE _FORMAT ;
exports . appHasDailyNotesPluginLoaded = appHasDailyNotesPluginLoaded ;
exports . appHasMonthlyNotesPluginLoaded = appHasMonthlyNotesPluginLoaded ;
exports . appHasQuarterlyNotesPluginLoaded = appHasQuarterlyNotesPluginLoaded ;
exports . appHasWeeklyNotesPluginLoaded = appHasWeeklyNotesPluginLoaded ;
exports . appHasYearlyNotesPluginLoaded = appHasYearlyNotesPluginLoaded ;
exports . createDailyNote = createDailyNote ;
exports . createMonthlyNote = createMonthlyNote ;
exports . createPeriodicNote = createPeriodicNote ;
exports . createQuarterlyNote = createQuarterlyNote ;
exports . createWeeklyNote = createWeeklyNote ;
exports . createYearlyNote = createYearlyNote ;
exports . getAllDailyNotes = getAllDailyNotes ;
exports . getAllMonthlyNotes = getAllMonthlyNotes ;
exports . getAllQuarterlyNotes = getAllQuarterlyNotes ;
exports . getAllWeeklyNotes = getAllWeeklyNotes ;
exports . getAllYearlyNotes = getAllYearlyNotes ;
exports . getDailyNote = getDailyNote ;
exports . getDailyNoteSettings = getDailyNoteSettings2 ;
exports . getDateFromFile = getDateFromFile ;
exports . getDateFromPath = getDateFromPath ;
exports . getDateUID = getDateUID ;
exports . getMonthlyNote = getMonthlyNote ;
exports . getMonthlyNoteSettings = getMonthlyNoteSettings ;
exports . getPeriodicNoteSettings = getPeriodicNoteSettings ;
exports . getQuarterlyNote = getQuarterlyNote ;
exports . getQuarterlyNoteSettings = getQuarterlyNoteSettings ;
exports . getTemplateInfo = getTemplateInfo ;
exports . getWeeklyNote = getWeeklyNote ;
exports . getWeeklyNoteSettings = getWeeklyNoteSettings ;
exports . getYearlyNote = getYearlyNote ;
exports . getYearlyNoteSettings = getYearlyNoteSettings ;
}
} ) ;
// src/main.ts
var main _exports = { } ;
_ _export ( main _exports , {
default : ( ) => ThePlugin
} ) ;
module . exports = _ _toCommonJS ( main _exports ) ;
var import _obsidian11 = require ( "obsidian" ) ;
// src/ui/SettingsTab.ts
var import _obsidian5 = require ( "obsidian" ) ;
// src/features/themes.ts
var import _obsidian3 = require ( "obsidian" ) ;
// src/features/githubUtils.ts
var import _obsidian = require ( "obsidian" ) ;
var GITHUB _RAW _USERCONTENT _PATH = "https://raw.githubusercontent.com/" ;
var grabReleaseFileFromRepository = async ( repository , version , fileName , debugLogging = true ) => {
const URL = ` https://github.com/ ${ repository } /releases/download/ ${ version } / ${ fileName } ` ;
try {
const download = await ( 0 , import _obsidian . request ) ( { url : URL } ) ;
return download === "Not Found" || download === ` {"error":"Not Found"} ` ? null : download ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabReleaseFileFromRepository" , URL , error ) ;
return null ;
}
} ;
var grabManifestJsonFromRepository = async ( repositoryPath , rootManifest = true , debugLogging = true ) => {
const manifestJsonPath = GITHUB _RAW _USERCONTENT _PATH + repositoryPath + ( rootManifest === true ? "/HEAD/manifest.json" : "/HEAD/manifest-beta.json" ) ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url : manifestJsonPath } ) ;
return response === "404: Not Found" ? null : await JSON . parse ( response ) ;
} catch ( error ) {
if ( error != "Error: Request failed, status 404" && debugLogging ) {
console . log ( ` error in grabManifestJsonFromRepository for ${ manifestJsonPath } ` , error ) ;
}
return null ;
}
} ;
var grabCommmunityPluginList = async ( debugLogging = true ) => {
const pluginListURL = ` https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-plugins.json ` ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url : pluginListURL } ) ;
return response === "404: Not Found" ? null : await JSON . parse ( response ) ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabCommmunityPluginList" , error ) ;
return null ;
}
} ;
var grabCommmunityThemesList = async ( debugLogging = true ) => {
const themesURL = ` https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-css-themes.json ` ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url : themesURL } ) ;
return response === "404: Not Found" ? null : await JSON . parse ( response ) ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabCommmunityThemesList" , error ) ;
return null ;
}
} ;
var grabCommmunityThemeCssFile = async ( repositoryPath , betaVersion = false , debugLogging ) => {
const themesURL = ` https://raw.githubusercontent.com/ ${ repositoryPath } /HEAD/theme ${ betaVersion ? "-beta" : "" } .css ` ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url : themesURL } ) ;
return response === "404: Not Found" ? null : response ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabCommmunityThemeCssFile" , error ) ;
return null ;
}
} ;
var grabCommmunityThemeManifestFile = async ( repositoryPath , debugLogging = true ) => {
const themesURL = ` https://raw.githubusercontent.com/ ${ repositoryPath } /HEAD/manifest.json ` ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url : themesURL } ) ;
return response === "404: Not Found" ? null : response ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabCommmunityThemeManifestFile" , error ) ;
return null ;
}
} ;
var checksum = ( str ) => {
let sum = 0 ;
for ( let i = 0 ; i < str . length ; i ++ ) {
sum += str . charCodeAt ( i ) ;
}
return sum ;
} ;
var checksumForString = ( str ) => {
return checksum ( str ) . toString ( ) ;
} ;
var grabChecksumOfThemeCssFile = async ( repositoryPath , betaVersion , debugLogging ) => {
const themeCSS = await grabCommmunityThemeCssFile ( repositoryPath , betaVersion , debugLogging ) ;
return themeCSS ? checksumForString ( themeCSS ) : "0" ;
} ;
var grabLastCommitInfoForAFile = async ( repositoryPath , path , debugLogging = true ) => {
const url = ` https://api.github.com/repos/ ${ repositoryPath } /commits?path= ${ path } &page=1&per_page=1 ` ;
try {
const response = await ( 0 , import _obsidian . request ) ( { url } ) ;
return response === "404: Not Found" ? null : JSON . parse ( response ) ;
} catch ( error ) {
if ( debugLogging )
console . log ( "error in grabLastCommitInfoForAFile" , error ) ;
return null ;
}
} ;
var grabLastCommitDateForAFile = async ( repositoryPath , path ) => {
const test = await grabLastCommitInfoForAFile ( repositoryPath , path ) ;
if ( test [ 0 ] . commit . committer . date ) {
return test [ 0 ] . commit . committer . date ;
} else
return "" ;
} ;
// src/ui/settings.ts
var DEFAULT _SETTINGS = {
pluginList : [ ] ,
pluginSubListFrozenVersion : [ ] ,
themesList : [ ] ,
updateAtStartup : false ,
updateThemesAtStartup : false ,
ribbonIconEnabled : true ,
loggingEnabled : false ,
loggingPath : "BRAT-log" ,
loggingVerboseEnabled : false ,
debuggingMode : true ,
notificationsEnabled : true
} ;
async function addBetaPluginToList ( plugin , repositoryPath , specifyVersion = "" ) {
let save = false ;
if ( ! plugin . settings . pluginList . contains ( repositoryPath ) ) {
plugin . settings . pluginList . unshift ( repositoryPath ) ;
save = true ;
}
if ( specifyVersion !== "" && plugin . settings . pluginSubListFrozenVersion . filter ( ( x ) => x . repo === repositoryPath ) . length === 0 ) {
plugin . settings . pluginSubListFrozenVersion . unshift ( {
repo : repositoryPath ,
version : specifyVersion
} ) ;
save = true ;
}
if ( save ) {
plugin . saveSettings ( ) ;
}
}
async function existBetaPluginInList ( plugin , repositoryPath ) {
return plugin . settings . pluginList . contains ( repositoryPath ) ;
}
async function addBetaThemeToList ( plugin , repositoryPath , themeCSS ) {
const newTheme = {
repo : repositoryPath ,
lastUpdate : checksumForString ( themeCSS )
} ;
plugin . settings . themesList . unshift ( newTheme ) ;
plugin . saveSettings ( ) ;
}
async function existBetaThemeinInList ( plugin , repositoryPath ) {
const testIfThemExists = plugin . settings . themesList . find ( ( t ) => t . repo === repositoryPath ) ;
return testIfThemExists ? true : false ;
}
function updateBetaThemeLastUpdateChecksum ( plugin , repositoryPath , checksum2 ) {
plugin . settings . themesList . forEach ( ( t ) => {
if ( t . repo === repositoryPath ) {
t . lastUpdate = checksum2 ;
plugin . saveSettings ( ) ;
}
} ) ;
}
// src/utils/notifications.ts
var import _obsidian2 = require ( "obsidian" ) ;
function ToastMessage ( plugin , msg , timeoutInSeconds = 10 , contextMenuCallback ) {
if ( plugin . settings . notificationsEnabled === false )
return ;
const additionalInfo = contextMenuCallback ? import _obsidian2 . Platform . isDesktop ? "(click=dismiss, right-click=Info)" : "(click=dismiss)" : "" ;
const newNotice = new import _obsidian2 . Notice ( ` BRAT
$ { msg }
$ { additionalInfo } ` , timeoutInSeconds * 1e3);
if ( contextMenuCallback )
newNotice . noticeEl . oncontextmenu = async ( ) => {
contextMenuCallback ( ) ;
} ;
}
// src/utils/internetconnection.ts
async function isConnectedToInternet ( ) {
try {
const online = await fetch ( "https://obsidian.md/?" + Math . random ( ) ) ;
return online . status >= 200 && online . status < 300 ;
} catch ( err ) {
return false ;
}
}
// src/features/themes.ts
var themeSave = async ( plugin , cssGithubRepository , newInstall ) => {
let themeCSS = await grabCommmunityThemeCssFile ( cssGithubRepository , true , plugin . settings . debuggingMode ) ;
if ( ! themeCSS )
themeCSS = await grabCommmunityThemeCssFile ( cssGithubRepository , false , plugin . settings . debuggingMode ) ;
if ( ! themeCSS ) {
ToastMessage ( plugin , "There is no theme.css or theme-beta.css file in the root path of this repository, so there is no theme to install." ) ;
return false ;
}
const themeManifest = await grabCommmunityThemeManifestFile ( cssGithubRepository , plugin . settings . debuggingMode ) ;
if ( ! themeManifest ) {
ToastMessage ( plugin , "There is no manifest.json file in the root path of this repository, so theme cannot be installed." ) ;
return false ;
}
const manifestInfo = await JSON . parse ( themeManifest ) ;
const themeTargetFolderPath = ( 0 , import _obsidian3 . normalizePath ) ( themesRootPath ( plugin ) + manifestInfo . name ) ;
const adapter = plugin . app . vault . adapter ;
if ( await adapter . exists ( themeTargetFolderPath ) === false )
await adapter . mkdir ( themeTargetFolderPath ) ;
await adapter . write ( ( 0 , import _obsidian3 . normalizePath ) ( themeTargetFolderPath + "/theme.css" ) , themeCSS ) ;
await adapter . write ( ( 0 , import _obsidian3 . normalizePath ) ( themeTargetFolderPath + "/manifest.json" ) , themeManifest ) ;
updateBetaThemeLastUpdateChecksum ( plugin , cssGithubRepository , checksumForString ( themeCSS ) ) ;
let msg = ` ` ;
if ( newInstall ) {
await addBetaThemeToList ( plugin , cssGithubRepository , themeCSS ) ;
msg = ` ${ manifestInfo . name } theme installed from ${ cssGithubRepository } . ` ;
setTimeout ( ( ) => {
plugin . app . customCss . setTheme ( manifestInfo . name ) ;
} , 500 ) ;
} else {
msg = ` ${ manifestInfo . name } theme updated from ${ cssGithubRepository } . ` ;
}
plugin . log ( msg + ` [Theme Info](https://github.com/ ${ cssGithubRepository } ) ` , false ) ;
ToastMessage ( plugin , ` ${ msg } ` , 20 , async ( ) => {
window . open ( ` https://github.com/ ${ cssGithubRepository } ` ) ;
} ) ;
return true ;
} ;
var themesCheckAndUpdates = async ( plugin , showInfo ) => {
if ( await isConnectedToInternet ( ) === false ) {
console . log ( "BRAT: No internet detected." ) ;
return ;
}
let newNotice ;
const msg1 = ` Checking for beta theme updates STARTED ` ;
plugin . log ( msg1 , true ) ;
if ( showInfo && plugin . settings . notificationsEnabled )
newNotice = new import _obsidian3 . Notice ( ` BRAT
$ { msg1 } ` , 3e4);
for ( const t of plugin . settings . themesList ) {
let lastUpdateOnline = await grabChecksumOfThemeCssFile ( t . repo , true , plugin . settings . debuggingMode ) ;
if ( lastUpdateOnline === "0" )
lastUpdateOnline = await grabChecksumOfThemeCssFile ( t . repo , false , plugin . settings . debuggingMode ) ;
if ( lastUpdateOnline !== t . lastUpdate )
await themeSave ( plugin , t . repo , false ) ;
}
const msg2 = ` Checking for beta theme updates COMPLETED ` ;
plugin . log ( msg2 , true ) ;
if ( showInfo ) {
if ( plugin . settings . notificationsEnabled )
newNotice . hide ( ) ;
ToastMessage ( plugin , msg2 ) ;
}
} ;
var themeDelete = async ( plugin , cssGithubRepository ) => {
plugin . settings . themesList = plugin . settings . themesList . filter ( ( t ) => t . repo != cssGithubRepository ) ;
plugin . saveSettings ( ) ;
const msg = ` Removed ${ cssGithubRepository } from BRAT themes list and will no longer be updated. However, the theme files still exist in the vault. To remove them, go into Settings > Appearance and remove the theme. ` ;
plugin . log ( msg , true ) ;
ToastMessage ( plugin , ` ${ msg } ` ) ;
} ;
var themesRootPath = ( plugin ) => {
return ( 0 , import _obsidian3 . normalizePath ) ( plugin . app . vault . configDir + "/themes" ) + "/" ;
} ;
// src/ui/AddNewTheme.ts
var import _obsidian4 = require ( "obsidian" ) ;
// src/ui/Promotional.ts
var promotionalLinks = ( containerEl , settingsTab = true ) => {
const linksDiv = containerEl . createEl ( "div" ) ;
linksDiv . style . float = "right" ;
if ( settingsTab === false ) {
linksDiv . style . padding = "10px" ;
linksDiv . style . paddingLeft = "15px" ;
linksDiv . style . paddingRight = "15px" ;
} else {
linksDiv . style . padding = "15px" ;
linksDiv . style . paddingLeft = "15px" ;
linksDiv . style . paddingRight = "15px" ;
linksDiv . style . marginLeft = "15px" ;
}
const twitterSpan = linksDiv . createDiv ( "coffee" ) ;
twitterSpan . addClass ( "ex-twitter-span" ) ;
twitterSpan . style . paddingLeft = "10px" ;
const captionText = twitterSpan . createDiv ( ) ;
captionText . innerText = "Learn more about my work at:" ;
twitterSpan . appendChild ( captionText ) ;
const twitterLink = twitterSpan . createEl ( "a" , { href : "https://tfthacker.com" } ) ;
twitterLink . innerText = "https://tfthacker.com" ;
return linksDiv ;
} ;
// src/ui/AddNewTheme.ts
var AddNewTheme = class extends import _obsidian4 . Modal {
constructor ( plugin , openSettingsTabAfterwards = false ) {
super ( plugin . app ) ;
this . plugin = plugin ;
this . address = "" ;
this . openSettingsTabAfterwards = openSettingsTabAfterwards ;
}
async submitForm ( ) {
if ( this . address === "" )
return ;
const scrubbedAddress = this . address . replace ( "https://github.com/" , "" ) ;
if ( await existBetaThemeinInList ( this . plugin , scrubbedAddress ) ) {
ToastMessage ( this . plugin , ` This plugin is already in the list for beta testing ` , 10 ) ;
return ;
}
if ( await themeSave ( this . plugin , scrubbedAddress , true ) ) {
this . close ( ) ;
}
}
onOpen ( ) {
this . contentEl . createEl ( "h4" , { text : "Github repository for beta theme:" } ) ;
this . contentEl . createEl ( "form" , { } , ( formEl ) => {
formEl . addClass ( "brat-modal" ) ;
new import _obsidian4 . Setting ( formEl ) . addText ( ( textEl ) => {
textEl . setPlaceholder ( "Repository (example: https://github.com/GitubUserName/repository-name" ) ;
textEl . onChange ( ( value ) => {
this . address = value . trim ( ) ;
} ) ;
textEl . inputEl . addEventListener ( "keydown" , async ( e ) => {
if ( e . key === "Enter" && this . address !== " " ) {
e . preventDefault ( ) ;
await this . submitForm ( ) ;
}
} ) ;
textEl . inputEl . style . width = "100%" ;
window . setTimeout ( ( ) => {
const title = document . querySelector ( ".setting-item-info" ) ;
if ( title )
title . remove ( ) ;
textEl . inputEl . focus ( ) ;
} , 10 ) ;
} ) ;
formEl . createDiv ( "modal-button-container" , ( buttonContainerEl ) => {
buttonContainerEl . createEl ( "button" , { attr : { type : "button" } , text : "Never mind" } ) . addEventListener ( "click" , ( ) => this . close ( ) ) ;
buttonContainerEl . createEl ( "button" , {
attr : { type : "submit" } ,
cls : "mod-cta" ,
text : "Add Theme"
} ) ;
} ) ;
const newDiv = formEl . createDiv ( ) ;
newDiv . style . borderTop = "1px solid #ccc" ;
newDiv . style . marginTop = "30px" ;
const byTfThacker = newDiv . createSpan ( ) ;
byTfThacker . innerHTML = "BRAT by <a href='https://bit.ly/o42-twitter'>TFTHacker</a>" ;
byTfThacker . style . fontStyle = "italic" ;
newDiv . appendChild ( byTfThacker ) ;
promotionalLinks ( newDiv , false ) ;
window . setTimeout ( ( ) => {
const title = formEl . querySelectorAll ( ".brat-modal .setting-item-info" ) ;
title . forEach ( ( titleEl ) => {
titleEl . remove ( ) ;
} ) ;
} , 50 ) ;
formEl . addEventListener ( "submit" , async ( e ) => {
e . preventDefault ( ) ;
if ( this . address !== "" )
await this . submitForm ( ) ;
} ) ;
} ) ;
}
async onClose ( ) {
if ( this . openSettingsTabAfterwards ) {
await this . plugin . app . setting . open ( ) ;
await this . plugin . app . setting . openTabById ( "obsidian42-brat" ) ;
}
}
} ;
// src/ui/SettingsTab.ts
var BratSettingsTab = class extends import _obsidian5 . PluginSettingTab {
constructor ( app , plugin ) {
super ( app , plugin ) ;
this . plugin = plugin ;
}
display ( ) {
const { containerEl } = this ;
containerEl . empty ( ) ;
promotionalLinks ( containerEl , true ) ;
containerEl . createEl ( "h1" , { text : this . plugin . appName } ) ;
containerEl . createEl ( "h2" , { text : "by TfTHacker" } ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Auto-update plugins at startup" ) . setDesc ( "If enabled all beta plugins will be checked for updates each time Obsidian starts. Note: this does not update frozen version plugins." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . updateAtStartup ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . updateAtStartup = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Auto-update themes at startup" ) . setDesc ( "If enabled all beta themes will be checked for updates each time Obsidian starts." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . updateThemesAtStartup ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . updateThemesAtStartup = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Ribbon Button" ) . setDesc ( "Toggle ribbon button off and on." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . ribbonIconEnabled ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . ribbonIconEnabled = value ;
if ( this . plugin . settings . ribbonIconEnabled === false )
this . plugin . ribbonIcon . remove ( ) ;
else
this . plugin . showRibbonButton ( ) ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
containerEl . createEl ( "hr" ) ;
containerEl . createEl ( "h2" , { text : "Beta Plugin List" } ) ;
containerEl . createEl ( "div" , { text : ` The following is a list of beta plugins added via the command palette "Add a beta plugin for testing" or "Add a beta plugin with frozen version for testing". A frozen version is a specific release of a plugin based on its releease tag. ` } ) ;
containerEl . createEl ( "p" ) ;
containerEl . createEl ( "div" , { text : ` Click the x button next to a plugin to remove it from the list. ` } ) ;
containerEl . createEl ( "p" ) ;
containerEl . createEl ( "span" ) . createEl ( "b" , { text : "Note: " } ) ;
containerEl . createSpan ( { text : "This does not delete the plugin, this should be done from the Community Plugins tab in Settings." } ) ;
new import _obsidian5 . Setting ( containerEl ) . addButton ( ( cb ) => {
cb . setButtonText ( "Add Beta plugin" ) ;
cb . onClick ( async ( ) => {
this . plugin . app . setting . close ( ) ;
await this . plugin . betaPlugins . displayAddNewPluginModal ( true , false ) ;
} ) ;
} ) ;
const pluginSubListFrozenVersionNames = new Set ( this . plugin . settings . pluginSubListFrozenVersion . map ( ( x ) => x . repo ) ) ;
for ( const bp of this . plugin . settings . pluginList ) {
if ( pluginSubListFrozenVersionNames . has ( bp ) ) {
continue ;
}
new import _obsidian5 . Setting ( containerEl ) . setName ( bp ) . addButton ( ( btn ) => {
btn . setIcon ( "cross" ) ;
btn . setTooltip ( "Delete this beta plugin" ) ;
btn . onClick ( async ( ) => {
if ( btn . buttonEl . textContent === "" )
btn . setButtonText ( "Click once more to confirm removal" ) ;
else {
btn . buttonEl . parentElement . parentElement . remove ( ) ;
await this . plugin . betaPlugins . deletePlugin ( bp ) ;
}
} ) ;
} ) ;
}
new import _obsidian5 . Setting ( containerEl ) . addButton ( ( cb ) => {
cb . setButtonText ( "Add Beta plugin with frozen version" ) ;
cb . onClick ( async ( ) => {
this . plugin . app . setting . close ( ) ;
await this . plugin . betaPlugins . displayAddNewPluginModal ( true , true ) ;
} ) ;
} ) ;
for ( const bp of this . plugin . settings . pluginSubListFrozenVersion ) {
new import _obsidian5 . Setting ( containerEl ) . setName ( ` ${ bp . repo } (version ${ bp . version } ) ` ) . addButton ( ( btn ) => {
btn . setIcon ( "cross" ) ;
btn . setTooltip ( "Delete this beta plugin" ) ;
btn . onClick ( async ( ) => {
if ( btn . buttonEl . textContent === "" )
btn . setButtonText ( "Click once more to confirm removal" ) ;
else {
btn . buttonEl . parentElement . parentElement . remove ( ) ;
await this . plugin . betaPlugins . deletePlugin ( bp . repo ) ;
}
} ) ;
} ) ;
}
containerEl . createEl ( "hr" ) ;
containerEl . createEl ( "h2" , { text : "Beta Themes List" } ) ;
new import _obsidian5 . Setting ( containerEl ) . addButton ( ( cb ) => {
cb . setButtonText ( "Add Beta Theme" ) ;
cb . onClick ( async ( ) => {
this . plugin . app . setting . close ( ) ;
new AddNewTheme ( this . plugin ) . open ( ) ;
} ) ;
} ) ;
for ( const bp of this . plugin . settings . themesList ) {
new import _obsidian5 . Setting ( containerEl ) . setName ( bp . repo ) . addButton ( ( btn ) => {
btn . setIcon ( "cross" ) ;
btn . setTooltip ( "Delete this beta theme" ) ;
btn . onClick ( async ( ) => {
if ( btn . buttonEl . textContent === "" )
btn . setButtonText ( "Click once more to confirm removal" ) ;
else {
btn . buttonEl . parentElement . parentElement . remove ( ) ;
await themeDelete ( this . plugin , bp . repo ) ;
}
} ) ;
} ) ;
}
containerEl . createEl ( "hr" ) ;
containerEl . createEl ( "h2" , { text : "Monitoring" } ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Enable Notifications" ) . setDesc ( "BRAT will provide popup notifications for its various activities. Turn this off means no notifications from BRAT." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . notificationsEnabled ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . notificationsEnabled = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Enable Logging" ) . setDesc ( "Plugin updates will be logged to a file in the log file." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . loggingEnabled ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . loggingEnabled = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( this . containerEl ) . setName ( "BRAT Log File Location" ) . setDesc ( "Logs will be saved to this file. Don't add .md to the file name." ) . addSearch ( ( cb ) => {
cb . setPlaceholder ( "Example: BRAT-log" ) . setValue ( this . plugin . settings . loggingPath ) . onChange ( async ( new _folder ) => {
this . plugin . settings . loggingPath = new _folder ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Enable Verbose Logging" ) . setDesc ( "Get a lot more information in the log." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . loggingVerboseEnabled ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . loggingVerboseEnabled = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
new import _obsidian5 . Setting ( containerEl ) . setName ( "Debugging Mode" ) . setDesc ( "Atomic Bomb level console logging. Can be used for troubleshoting and development." ) . addToggle ( ( cb ) => {
cb . setValue ( this . plugin . settings . debuggingMode ) ;
cb . onChange ( async ( value ) => {
this . plugin . settings . debuggingMode = value ;
await this . plugin . saveSettings ( ) ;
} ) ;
} ) ;
}
} ;
// src/ui/AddNewPluginModal.ts
var import _obsidian6 = require ( "obsidian" ) ;
var AddNewPluginModal = class extends import _obsidian6 . Modal {
constructor ( plugin , betaPlugins , openSettingsTabAfterwards = false , useFrozenVersion = false ) {
super ( plugin . app ) ;
this . plugin = plugin ;
this . betaPlugins = betaPlugins ;
this . address = "" ;
this . openSettingsTabAfterwards = openSettingsTabAfterwards ;
this . useFrozenVersion = useFrozenVersion ;
this . version = "" ;
}
async submitForm ( ) {
if ( this . address === "" )
return ;
let scrubbedAddress = this . address . replace ( "https://github.com/" , "" ) ;
if ( scrubbedAddress . endsWith ( ".git" ) )
scrubbedAddress = scrubbedAddress . slice ( 0 , - 4 ) ;
if ( await existBetaPluginInList ( this . plugin , scrubbedAddress ) ) {
ToastMessage ( this . plugin , ` This plugin is already in the list for beta testing ` , 10 ) ;
return ;
}
const result = await this . betaPlugins . addPlugin ( scrubbedAddress , false , false , false , this . version ) ;
if ( result ) {
this . close ( ) ;
}
}
onOpen ( ) {
this . contentEl . createEl ( "h4" , { text : "Github repository for beta plugin:" } ) ;
this . contentEl . createEl ( "form" , { } , ( formEl ) => {
formEl . addClass ( "brat-modal" ) ;
new import _obsidian6 . Setting ( formEl ) . addText ( ( textEl ) => {
textEl . setPlaceholder ( "Repository (example: https://github.com/GitubUserName/repository-name)" ) ;
textEl . onChange ( ( value ) => {
this . address = value . trim ( ) ;
} ) ;
textEl . inputEl . addEventListener ( "keydown" , async ( e ) => {
if ( e . key === "Enter" && this . address !== " " ) {
if ( this . useFrozenVersion && this . version !== "" || ! this . useFrozenVersion ) {
e . preventDefault ( ) ;
await this . submitForm ( ) ;
}
}
} ) ;
textEl . inputEl . style . width = "100%" ;
} ) ;
if ( this . useFrozenVersion ) {
new import _obsidian6 . Setting ( formEl ) . addText ( ( textEl ) => {
textEl . setPlaceholder ( "Specify the release version tag (example: 1.0.0)" ) ;
textEl . onChange ( ( value ) => {
this . version = value . trim ( ) ;
} ) ;
textEl . inputEl . style . width = "100%" ;
} ) ;
}
formEl . createDiv ( "modal-button-container" , ( buttonContainerEl ) => {
buttonContainerEl . createEl ( "button" , { attr : { type : "button" } , text : "Never mind" } ) . addEventListener ( "click" , ( ) => this . close ( ) ) ;
buttonContainerEl . createEl ( "button" , {
attr : { type : "submit" } ,
cls : "mod-cta" ,
text : "Add Plugin"
} ) ;
} ) ;
const newDiv = formEl . createDiv ( ) ;
newDiv . style . borderTop = "1px solid #ccc" ;
newDiv . style . marginTop = "30px" ;
const byTfThacker = newDiv . createSpan ( ) ;
byTfThacker . innerHTML = "BRAT by <a href='https://bit.ly/o42-twitter'>TFTHacker</a>" ;
byTfThacker . style . fontStyle = "italic" ;
newDiv . appendChild ( byTfThacker ) ;
promotionalLinks ( newDiv , false ) ;
window . setTimeout ( ( ) => {
const title = formEl . querySelectorAll ( ".brat-modal .setting-item-info" ) ;
title . forEach ( ( titleEl ) => {
titleEl . remove ( ) ;
} ) ;
} , 50 ) ;
formEl . addEventListener ( "submit" , async ( e ) => {
e . preventDefault ( ) ;
if ( this . address !== "" ) {
if ( this . useFrozenVersion && this . version !== "" || ! this . useFrozenVersion ) {
await this . submitForm ( ) ;
}
}
} ) ;
} ) ;
}
async onClose ( ) {
if ( this . openSettingsTabAfterwards ) {
await this . plugin . app . setting . open ( ) ;
await this . plugin . app . setting . openTabById ( "obsidian42-brat" ) ;
}
}
} ;
// src/features/BetaPlugins.ts
var import _obsidian7 = require ( "obsidian" ) ;
var BetaPlugins = class {
constructor ( plugin ) {
this . plugin = plugin ;
}
/ * *
* opens the AddNewPluginModal to get info for a new beta plugin
* @ param { boolean } openSettingsTabAfterwards will open settings screen afterwards . Used when this command is called from settings tab
* @ param { boolean } useFrozenVersion install the plugin using frozen version .
* @ return { < Promise > < void > }
* /
async displayAddNewPluginModal ( openSettingsTabAfterwards = false , useFrozenVersion = false ) {
const newPlugin = new AddNewPluginModal ( this . plugin , this , openSettingsTabAfterwards , useFrozenVersion ) ;
newPlugin . open ( ) ;
}
/ * *
* Validates that a GitHub repository is plugin
*
* @ param { string } repositoryPath GithubUser / RepositoryName ( example : TfThacker / obsidian42 - brat )
* @ param { [ type ] } getBetaManifest test the beta version of the manifest , not at the root
* @ param { [ type ] } false [ false description ]
* @ param { [ type ] } reportIssues will display notices as it finds issues
*
* @ return { Promise < PluginManifest > } the manifest file if found , or null if its incomplete
* /
async validateRepository ( repositoryPath , getBetaManifest = false , reportIssues = false ) {
const noticeTimeout = 15 ;
const manifestJson = await grabManifestJsonFromRepository ( repositoryPath , ! getBetaManifest , this . plugin . settings . debuggingMode ) ;
if ( ! manifestJson ) {
if ( reportIssues )
ToastMessage ( this . plugin , ` ${ repositoryPath }
This does not seem to be an obsidian plugin , as there is no manifest . json file . ` , noticeTimeout);
return null ;
}
if ( ! ( "id" in manifestJson ) ) {
if ( reportIssues )
ToastMessage ( this . plugin , ` ${ repositoryPath }
The plugin id attribute for the release is missing from the manifest file ` , noticeTimeout);
return null ;
}
if ( ! ( "version" in manifestJson ) ) {
if ( reportIssues )
ToastMessage ( this . plugin , ` ${ repositoryPath }
The version attribute for the release is missing from the manifest file ` , noticeTimeout);
return null ;
}
return manifestJson ;
}
/ * *
* Gets all the release files based on the version number in the manifest
*
* @ param { string } repositoryPath path to the GitHub repository
* @ param { PluginManifest < ReleaseFiles > } manifest manifest file
* @ param { boolean } getManifest grab the remote manifest file
* @ param { string } specifyVersion grab the specified version if set
*
* @ return { Promise < ReleaseFiles > } all relase files as strings based on the ReleaseFiles interaface
* /
async getAllReleaseFiles ( repositoryPath , manifest , getManifest , specifyVersion = "" ) {
const version = specifyVersion === "" ? manifest . version : specifyVersion ;
const reallyGetManifestOrNot = getManifest || specifyVersion !== "" ;
return {
mainJs : await grabReleaseFileFromRepository ( repositoryPath , version , "main.js" , this . plugin . settings . debuggingMode ) ,
manifest : reallyGetManifestOrNot ? await grabReleaseFileFromRepository ( repositoryPath , version , "manifest.json" , this . plugin . settings . debuggingMode ) : "" ,
styles : await grabReleaseFileFromRepository ( repositoryPath , version , "styles.css" , this . plugin . settings . debuggingMode )
} ;
}
/ * *
* Writes the plugin release files to the local obsidian . plugins folder
*
* @ param { string } betaPluginID the id of the plugin ( not the repository path )
* @ param { ReleaseFiles < void > } relFiles release file as strings , based on the ReleaseFiles interface
*
* @ return { Promise < void > }
* /
async writeReleaseFilesToPluginFolder ( betaPluginID , relFiles ) {
const pluginTargetFolderPath = ( 0 , import _obsidian7 . normalizePath ) ( this . plugin . app . vault . configDir + "/plugins/" + betaPluginID ) + "/" ;
const adapter = this . plugin . app . vault . adapter ;
if ( await adapter . exists ( pluginTargetFolderPath ) === false || ! await adapter . exists ( pluginTargetFolderPath + "manifest.json" ) ) {
await adapter . mkdir ( pluginTargetFolderPath ) ;
}
await adapter . write ( pluginTargetFolderPath + "main.js" , relFiles . mainJs ) ;
await adapter . write ( pluginTargetFolderPath + "manifest.json" , relFiles . manifest ) ;
if ( relFiles . styles )
await adapter . write ( pluginTargetFolderPath + "styles.css" , relFiles . styles ) ;
}
/ * *
* Primary function for adding a new beta plugin to Obsidian .
* Also this function is used for updating existing plugins .
*
* @ param { string } repositoryPath path to GitHub repository formated as USERNAME / repository
* @ param { boolean } updatePluginFiles true if this is just an update not an install
* @ param { boolean } seeIfUpdatedOnly if true , and updatePluginFiles true , will just check for updates , but not do the update . will report to user that there is a new plugin
* @ param { boolean } reportIfNotUpdted if true , report if an update has not succed
* @ param { string } specifyVersion if not empty , need to install a specified version instead of the value in manifest { - beta } . json
* @ param { boolean } forceReinstall if true , will force a reinstall of the plugin , even if it is already installed
*
* @ return { Promise < boolean > } true if succeeds
* /
async addPlugin ( repositoryPath , updatePluginFiles = false , seeIfUpdatedOnly = false , reportIfNotUpdted = false , specifyVersion = "" , forceReinstall = false ) {
var _a ;
const noticeTimeout = 10 ;
let primaryManifest = await this . validateRepository ( repositoryPath , true , false ) ;
const usingBetaManifest = primaryManifest ? true : false ;
if ( usingBetaManifest === false )
primaryManifest = await this . validateRepository ( repositoryPath , false , true ) ;
if ( primaryManifest === null ) {
const msg = ` ${ repositoryPath }
A manifest . json or manifest - beta . json file does not exist in the root directory of the repository . This plugin cannot be installed . ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , ` ${ msg } ` , noticeTimeout ) ;
return false ;
}
if ( ! primaryManifest . hasOwnProperty ( "version" ) ) {
const msg = ` ${ repositoryPath }
The manifest$ { usingBetaManifest ? "-beta" : "" } . json file in the root directory of the repository does not have a version number in the file . This plugin cannot be installed . ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , ` ${ msg } ` , noticeTimeout ) ;
return false ;
}
if ( primaryManifest . hasOwnProperty ( "minAppVersion" ) ) {
if ( ! ( 0 , import _obsidian7 . requireApiVersion ) ( primaryManifest . minAppVersion ) ) {
const msg = ` Plugin: ${ repositoryPath }
The manifest$ { usingBetaManifest ? "-beta" : "" } . json for this plugin indicates that the Obsidian version of the app needs to be $ { primaryManifest . minAppVersion } , but this installation of Obsidian is $ { import _obsidian7 . apiVersion } .
You will need to update your Obsidian to use this plugin or contact the plugin developer for more information . ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , ` ${ msg } ` , 30 ) ;
return false ;
}
}
const getRelease = async ( ) => {
const rFiles = await this . getAllReleaseFiles ( repositoryPath , primaryManifest , usingBetaManifest , specifyVersion ) ;
if ( usingBetaManifest || rFiles . manifest === "" )
rFiles . manifest = JSON . stringify ( primaryManifest ) ;
if ( rFiles . mainJs === null ) {
const msg = ` ${ repositoryPath }
The release is not complete and cannot be download . main . js is missing from the Release ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , ` ${ msg } ` , noticeTimeout ) ;
return null ;
}
return rFiles ;
} ;
if ( updatePluginFiles === false || forceReinstall === true ) {
const releaseFiles = await getRelease ( ) ;
if ( releaseFiles === null )
return false ;
await this . writeReleaseFilesToPluginFolder ( primaryManifest . id , releaseFiles ) ;
if ( forceReinstall === false )
await addBetaPluginToList ( this . plugin , repositoryPath , specifyVersion ) ;
await this . plugin . app . plugins . loadManifests ( ) ;
if ( forceReinstall === true ) {
await this . reloadPlugin ( primaryManifest . id ) ;
this . plugin . log ( ` ${ repositoryPath } reinstalled ` , true ) ;
ToastMessage ( this . plugin , ` ${ repositoryPath }
Plugin has been reinstalled and reloaded . ` , noticeTimeout);
} else {
const versionText = specifyVersion === "" ? "" : ` (version: ${ specifyVersion } ) ` ;
const msg = ` ${ repositoryPath } ${ versionText }
The plugin has been registered with BRAT . You may still need to enable it the Community Plugin List . ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , msg , noticeTimeout ) ;
}
} else {
const pluginTargetFolderPath = this . plugin . app . vault . configDir + "/plugins/" + primaryManifest . id + "/" ;
let localManifestContents = "" ;
try {
localManifestContents = await this . plugin . app . vault . adapter . read ( pluginTargetFolderPath + "manifest.json" ) ;
} catch ( e ) {
if ( e . errno === - 4058 || e . errno === - 2 ) {
await this . addPlugin ( repositoryPath , false , usingBetaManifest , false , specifyVersion ) ;
return true ;
} else
console . log ( "BRAT - Local Manifest Load" , primaryManifest . id , JSON . stringify ( e , null , 2 ) ) ;
}
if ( specifyVersion !== "" || this . plugin . settings . pluginSubListFrozenVersion . map ( ( x ) => x . repo ) . includes ( repositoryPath ) ) {
ToastMessage ( this . plugin , ` The version of ${ repositoryPath } is frozen, not updating. ` , 3 ) ;
return false ;
}
const localManifestJSON = await JSON . parse ( localManifestContents ) ;
if ( localManifestJSON . version !== primaryManifest . version ) {
const releaseFiles = await getRelease ( ) ;
if ( releaseFiles === null )
return false ;
if ( seeIfUpdatedOnly ) {
const msg = ` There is an update available for ${ primaryManifest . id } from version ${ localManifestJSON . version } to ${ primaryManifest . version } . ` ;
this . plugin . log ( msg + ` [Release Info](https://github.com/ ${ repositoryPath } /releases/tag/ ${ primaryManifest . version } ) ` , false ) ;
ToastMessage ( this . plugin , msg , 30 , async ( ) => {
window . open ( ` https://github.com/ ${ repositoryPath } /releases/tag/ ${ primaryManifest . version } ` ) ;
} ) ;
} else {
await this . writeReleaseFilesToPluginFolder ( primaryManifest . id , releaseFiles ) ;
await this . plugin . app . plugins . loadManifests ( ) ;
if ( ( _a = this . plugin . app . plugins . plugins [ primaryManifest . id ] ) == null ? void 0 : _a . manifest )
await this . reloadPlugin ( primaryManifest . id ) ;
const msg = ` ${ primaryManifest . id }
Plugin has been updated from version $ { localManifestJSON . version } to $ { primaryManifest . version } . ` ;
this . plugin . log ( msg + ` [Release Info](https://github.com/ ${ repositoryPath } /releases/tag/ ${ primaryManifest . version } ) ` , false ) ;
ToastMessage ( this . plugin , msg , 30 , async ( ) => {
window . open ( ` https://github.com/ ${ repositoryPath } /releases/tag/ ${ primaryManifest . version } ` ) ;
} ) ;
}
} else if ( reportIfNotUpdted )
ToastMessage ( this . plugin , ` No update available for ${ repositoryPath } ` , 3 ) ;
}
return true ;
}
/ * *
* reloads a plugin ( assuming it has been enabled by user )
* pjeby , Thanks Bro https : //github.com/pjeby/hot-reload/blob/master/main.js
*
* @ param { string < void > } pluginName name of plugin
*
* @ return { Promise < void > }
* /
async reloadPlugin ( pluginName ) {
const plugins = this . plugin . app . plugins ;
try {
await plugins . disablePlugin ( pluginName ) ;
await plugins . enablePlugin ( pluginName ) ;
} catch ( e ) {
if ( this . plugin . settings . debuggingMode )
console . log ( "reload plugin" , e ) ;
}
}
/ * *
* updates a beta plugin
*
* @ param { string } repositoryPath repository path on GitHub
* @ param { boolean } onlyCheckDontUpdate only looks for update
*
* @ return { Promise < void > }
* /
async updatePlugin ( repositoryPath , onlyCheckDontUpdate = false , reportIfNotUpdted = false , forceReinstall = false ) {
const result = await this . addPlugin ( repositoryPath , true , onlyCheckDontUpdate , reportIfNotUpdted , "" , forceReinstall ) ;
if ( result === false && onlyCheckDontUpdate === false )
ToastMessage ( this . plugin , ` ${ repositoryPath }
Update of plugin failed . ` );
return result ;
}
/ * *
* walks through the list of plugins without frozen version and performs an update
*
* @ param { boolean } showInfo should this with a started / completed message - useful when ran from CP
* @ return { Promise < void > }
* /
async checkForUpdatesAndInstallUpdates ( showInfo = false , onlyCheckDontUpdate = false ) {
if ( await isConnectedToInternet ( ) === false ) {
console . log ( "BRAT: No internet detected." ) ;
return ;
}
let newNotice ;
const msg1 = ` Checking for plugin updates STARTED ` ;
this . plugin . log ( msg1 , true ) ;
if ( showInfo && this . plugin . settings . notificationsEnabled )
newNotice = new import _obsidian7 . Notice ( ` BRAT
$ { msg1 } ` , 3e4);
const pluginSubListFrozenVersionNames = new Set ( this . plugin . settings . pluginSubListFrozenVersion . map ( ( f ) => f . repo ) ) ;
for ( const bp of this . plugin . settings . pluginList ) {
if ( pluginSubListFrozenVersionNames . has ( bp ) ) {
continue ;
}
await this . updatePlugin ( bp , onlyCheckDontUpdate ) ;
}
const msg2 = ` Checking for plugin updates COMPLETED ` ;
this . plugin . log ( msg2 , true ) ;
if ( showInfo ) {
newNotice . hide ( ) ;
ToastMessage ( this . plugin , msg2 , 10 ) ;
}
}
/ * *
* Removes the beta plugin from the list of beta plugins ( does not delete them from disk )
*
* @ param { string < void > } betaPluginID repository path
*
* @ return { Promise < void > } [ return description ]
* /
async deletePlugin ( repositoryPath ) {
const msg = ` Removed ${ repositoryPath } from BRAT plugin list ` ;
this . plugin . log ( msg , true ) ;
this . plugin . settings . pluginList = this . plugin . settings . pluginList . filter ( ( b ) => b != repositoryPath ) ;
this . plugin . settings . pluginSubListFrozenVersion = this . plugin . settings . pluginSubListFrozenVersion . filter (
( b ) => b . repo != repositoryPath
) ;
this . plugin . saveSettings ( ) ;
}
/ * *
* Returns a list of plugins that are currently enabled or currently disabled
*
* @ param { boolean [ ] } enabled true for enabled plugins , false for disabled plutings
*
* @ return { PluginManifest [ ] } manifests of plugins
* /
getEnabledDisabledPlugins ( enabled ) {
const pl = this . plugin . app . plugins ;
const manifests = Object . values ( pl . manifests ) ;
const enabledPlugins = Object . values ( pl . plugins ) . map ( ( p ) => p . manifest ) ;
return enabled ? manifests . filter ( ( manifest ) => enabledPlugins . find ( ( pluginName ) => manifest . id === pluginName . id ) ) : manifests . filter ( ( manifest ) => ! enabledPlugins . find ( ( pluginName ) => manifest . id === pluginName . id ) ) ;
}
} ;
// src/ui/icons.ts
var import _obsidian8 = require ( "obsidian" ) ;
function addIcons ( ) {
( 0 , import _obsidian8 . addIcon ) (
"BratIcon" ,
` <path fill="currentColor" stroke="currentColor" d="M 41.667969 41.667969 C 41.667969 39.367188 39.800781 37.5 37.5 37.5 C 35.199219 37.5 33.332031 39.367188 33.332031 41.667969 C 33.332031 43.96875 35.199219 45.832031 37.5 45.832031 C 39.800781 45.832031 41.667969 43.96875 41.667969 41.667969 Z M 60.417969 58.582031 C 59.460938 58.023438 58.320312 57.867188 57.25 58.148438 C 56.179688 58.429688 55.265625 59.125 54.707031 60.082031 C 53.746094 61.777344 51.949219 62.820312 50 62.820312 C 48.050781 62.820312 46.253906 61.777344 45.292969 60.082031 C 44.734375 59.125 43.820312 58.429688 42.75 58.148438 C 41.679688 57.867188 40.539062 58.023438 39.582031 58.582031 C 37.597656 59.726562 36.910156 62.257812 38.042969 64.25 C 40.5 68.53125 45.0625 71.171875 50 71.171875 C 54.9375 71.171875 59.5 68.53125 61.957031 64.25 C 63.089844 62.257812 62.402344 59.726562 60.417969 58.582031 Z M 62.5 37.5 C 60.199219 37.5 58.332031 39.367188 58.332031 41.667969 C 58.332031 43.96875 60.199219 45.832031 62.5 45.832031 C 64.800781 45.832031 66.667969 43.96875 66.667969 41.667969 C 66.667969 39.367188 64.800781 37.5 62.5 37.5 Z M 50 8.332031 C 26.988281 8.332031 8.332031 26.988281 8.332031 50 C 8.332031 73.011719 26.988281 91.667969 50 91.667969 C 73.011719 91.667969 91.667969 73.011719 91.667969 50 C 91.667969 26.988281 73.011719 8.332031 50 8.332031 Z M 50 83.332031 C 33.988281 83.402344 20.191406 72.078125 17.136719 56.363281 C 14.078125 40.644531 22.628906 24.976562 37.5 19.042969 C 37.457031 19.636719 37.457031 20.238281 37.5 20.832031 C 37.5 27.738281 43.097656 33.332031 50 33.332031 C 52.300781 33.332031 54.167969 31.46875 54.167969 29.167969 C 54.167969 26.867188 52.300781 25 50 25 C 47.699219 25 45.832031 23.132812 45.832031 20.832031 C 45.832031 18.53125 47.699219 16.667969 50 16.667969 C 68.410156 16.667969 83.332031 31.589844 83.332031 50 C 83.332031 68.410156 68.410156 83.332031 50 83.332031 Z M 50 83.332031 " /> `
) ;
}
// src/utils/logging.ts
var import _obsidian9 = require ( "obsidian" ) ;
var import _obsidian _daily _notes _interface = _ _toESM ( require _main ( ) ) ;
function logger ( plugin , textToLog , verboseLoggingOn = false ) {
if ( plugin . settings . debuggingMode )
console . log ( "BRAT: " + textToLog ) ;
if ( plugin . settings . loggingEnabled ) {
if ( plugin . settings . loggingVerboseEnabled === false && verboseLoggingOn === true ) {
return ;
} else {
const fileName = plugin . settings . loggingPath + ".md" ;
const dateOutput = "[[" + ( 0 , import _obsidian9 . moment ) ( ) . format ( ( 0 , import _obsidian _daily _notes _interface . getDailyNoteSettings ) ( ) . format ) . toString ( ) + "]] " + ( 0 , import _obsidian9 . moment ) ( ) . format ( "HH:mm" ) ;
const machineName = import _obsidian9 . Platform . isDesktop ? window . require ( "os" ) . hostname ( ) : "MOBILE" ;
let output = dateOutput + " " + machineName + " " + textToLog . replace ( "\n" , " " ) + "\n\n" ;
setTimeout ( async ( ) => {
if ( await plugin . app . vault . adapter . exists ( fileName ) === true ) {
const fileContents = await plugin . app . vault . adapter . read ( fileName ) ;
output = output + fileContents ;
const file = plugin . app . vault . getAbstractFileByPath ( fileName ) ;
await plugin . app . vault . modify ( file , output ) ;
} else
await plugin . app . vault . create ( fileName , output ) ;
} , 10 ) ;
}
}
}
// src/ui/GenericFuzzySuggester.ts
var import _obsidian10 = require ( "obsidian" ) ;
var GenericFuzzySuggester = class extends import _obsidian10 . FuzzySuggestModal {
constructor ( plugin ) {
super ( plugin . app ) ;
this . scope . register ( [ "Shift" ] , "Enter" , ( evt ) => this . enterTrigger ( evt ) ) ;
this . scope . register ( [ "Ctrl" ] , "Enter" , ( evt ) => this . enterTrigger ( evt ) ) ;
}
setSuggesterData ( suggesterData ) {
this . data = suggesterData ;
}
async display ( callBack ) {
this . callbackFunction = callBack ;
this . open ( ) ;
}
getItems ( ) {
return this . data ;
}
getItemText ( item ) {
return item . display ;
}
onChooseItem ( ) {
return ;
}
// required by TS, but not using
renderSuggestion ( item , el ) {
el . createEl ( "div" , { text : item . item . display } ) ;
}
enterTrigger ( evt ) {
const selectedText = document . querySelector ( ".suggestion-item.is-selected div" ) . textContent ;
const item = this . data . find ( ( i ) => i . display === selectedText ) ;
if ( item ) {
this . invokeCallback ( item , evt ) ;
this . close ( ) ;
}
}
onChooseSuggestion ( item , evt ) {
this . invokeCallback ( item . item , evt ) ;
}
invokeCallback ( item , evt ) {
this . callbackFunction ( item , evt ) ;
}
} ;
// src/ui/PluginCommands.ts
var PluginCommands = class {
constructor ( plugin ) {
this . bratCommands = [
{
id : "BRAT-AddBetaPlugin" ,
icon : "BratIcon" ,
name : "Plugins: Add a beta plugin for testing" ,
showInRibbon : true ,
callback : async ( ) => {
await this . plugin . betaPlugins . displayAddNewPluginModal ( false , false ) ;
}
} ,
{
id : "BRAT-AddBetaPluginWithFrozenVersion" ,
icon : "BratIcon" ,
name : "Plugins: Add a beta plugin with frozen version based on a release tag" ,
showInRibbon : true ,
callback : async ( ) => {
await this . plugin . betaPlugins . displayAddNewPluginModal ( false , true ) ;
}
} ,
{
id : "BRAT-checkForUpdatesAndUpdate" ,
icon : "BratIcon" ,
name : "Plugins: Check for updates to all beta plugins and UPDATE" ,
showInRibbon : true ,
callback : async ( ) => {
await this . plugin . betaPlugins . checkForUpdatesAndInstallUpdates ( true , false ) ;
}
} ,
{
id : "BRAT-checkForUpdatesAndDontUpdate" ,
icon : "BratIcon" ,
name : "Plugins: Only check for updates to beta plugins, but don't Update" ,
showInRibbon : true ,
callback : async ( ) => {
await this . plugin . betaPlugins . checkForUpdatesAndInstallUpdates ( true , true ) ;
}
} ,
{
id : "BRAT-updateOnePlugin" ,
icon : "BratIcon" ,
name : "Plugins: Choose a single plugin version to update" ,
showInRibbon : true ,
callback : async ( ) => {
const pluginSubListFrozenVersionNames = new Set ( this . plugin . settings . pluginSubListFrozenVersion . map ( ( f ) => f . repo ) ) ;
const pluginList = Object . values ( this . plugin . settings . pluginList ) . filter ( ( f ) => ! pluginSubListFrozenVersionNames . has ( f ) ) . map ( ( m ) => {
return { display : m , info : m } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( pluginList ) ;
await gfs . display ( async ( results ) => {
const msg = ` Checking for updates for ${ results . info } ` ;
this . plugin . log ( msg , true ) ;
ToastMessage ( this . plugin , `
$ { msg } ` , 3);
await this . plugin . betaPlugins . updatePlugin ( results . info , false , true ) ;
} ) ;
}
} ,
{
id : "BRAT-reinstallOnePlugin" ,
icon : "BratIcon" ,
name : "Plugins: Choose a single plugin to reinstall" ,
showInRibbon : true ,
callback : async ( ) => {
const pluginSubListFrozenVersionNames = new Set ( this . plugin . settings . pluginSubListFrozenVersion . map ( ( f ) => f . repo ) ) ;
const pluginList = Object . values ( this . plugin . settings . pluginList ) . filter ( ( f ) => ! pluginSubListFrozenVersionNames . has ( f ) ) . map ( ( m ) => {
return { display : m , info : m } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( pluginList ) ;
await gfs . display ( async ( results ) => {
const msg = ` Reinstalling ${ results . info } ` ;
ToastMessage ( this . plugin , `
$ { msg } ` , 3);
this . plugin . log ( msg , true ) ;
await this . plugin . betaPlugins . updatePlugin ( results . info , false , false , true ) ;
} ) ;
}
} ,
{
id : "BRAT-restartPlugin" ,
icon : "BratIcon" ,
name : "Plugins: Restart a plugin that is already installed" ,
showInRibbon : true ,
callback : async ( ) => {
const pluginList = Object . values ( this . plugin . app . plugins . manifests ) . map ( ( m ) => {
return { display : m . id , info : m . id } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( pluginList ) ;
await gfs . display ( async ( results ) => {
ToastMessage ( this . plugin , ` ${ results . info }
Plugin reloading ... . . ` , 5);
await this . plugin . betaPlugins . reloadPlugin ( results . info ) ;
} ) ;
}
} ,
{
id : "BRAT-disablePlugin" ,
icon : "BratIcon" ,
name : "Plugins: Disable a plugin - toggle it off" ,
showInRibbon : true ,
callback : async ( ) => {
const pluginList = this . plugin . betaPlugins . getEnabledDisabledPlugins ( true ) . map ( ( manifest ) => {
return { display : ` ${ manifest . name } ( ${ manifest . id } ) ` , info : manifest . id } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( pluginList ) ;
await gfs . display ( async ( results ) => {
this . plugin . log ( ` ${ results . display } plugin disabled ` , false ) ;
if ( this . plugin . settings . debuggingMode )
console . log ( results . info ) ;
await this . plugin . app . plugins . disablePluginAndSave ( results . info ) ;
} ) ;
}
} ,
{
id : "BRAT-enablePlugin" ,
icon : "BratIcon" ,
name : "Plugins: Enable a plugin - toggle it on" ,
showInRibbon : true ,
callback : async ( ) => {
const pluginList = this . plugin . betaPlugins . getEnabledDisabledPlugins ( false ) . map ( ( manifest ) => {
return { display : ` ${ manifest . name } ( ${ manifest . id } ) ` , info : manifest . id } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( pluginList ) ;
await gfs . display ( async ( results ) => {
this . plugin . log ( ` ${ results . display } plugin enabled ` , false ) ;
await this . plugin . app . plugins . enablePluginAndSave ( results . info ) ;
} ) ;
}
} ,
{
id : "BRAT-openGitHubZRepository" ,
icon : "BratIcon" ,
name : "Plugins: Open the GitHub repository for a plugin" ,
showInRibbon : true ,
callback : async ( ) => {
const communityPlugins = await grabCommmunityPluginList ( this . plugin . settings . debuggingMode ) ;
const communityPluginList = Object . values ( communityPlugins ) . map ( ( p ) => {
return { display : ` Plugin: ${ p . name } ( ${ p . repo } ) ` , info : p . repo } ;
} ) ;
const bratList = Object . values ( this . plugin . settings . pluginList ) . map ( ( p ) => {
return { display : "BRAT: " + p , info : p } ;
} ) ;
communityPluginList . forEach ( ( si ) => bratList . push ( si ) ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( bratList ) ;
await gfs . display ( async ( results ) => {
if ( results . info )
window . open ( ` https://github.com/ ${ results . info } ` ) ;
} ) ;
}
} ,
{
id : "BRAT-openGitHubRepoTheme" ,
icon : "BratIcon" ,
name : "Themes: Open the GitHub repository for a theme (appearance)" ,
showInRibbon : true ,
callback : async ( ) => {
const communityTheme = await grabCommmunityThemesList ( this . plugin . settings . debuggingMode ) ;
const communityThemeList = Object . values ( communityTheme ) . map ( ( p ) => {
return { display : ` Theme: ${ p . name } ( ${ p . repo } ) ` , info : p . repo } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
gfs . setSuggesterData ( communityThemeList ) ;
await gfs . display ( async ( results ) => {
if ( results . info )
window . open ( ` https://github.com/ ${ results . info } ` ) ;
} ) ;
}
} ,
{
id : "BRAT-opentPluginSettings" ,
icon : "BratIcon" ,
name : "Plugins: Open Plugin Settings Tab" ,
showInRibbon : true ,
callback : async ( ) => {
const settings = this . plugin . app . setting ;
const listOfPluginSettingsTabs = Object . values ( settings . pluginTabs ) . map ( ( t ) => {
return { display : "Plugin: " + t . name , info : t . id } ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
const listOfCoreSettingsTabs = Object . values ( settings . settingTabs ) . map ( ( t ) => {
return { display : "Core: " + t . name , info : t . id } ;
} ) ;
listOfPluginSettingsTabs . forEach ( ( si ) => listOfCoreSettingsTabs . push ( si ) ) ;
gfs . setSuggesterData ( listOfCoreSettingsTabs ) ;
await gfs . display ( async ( results ) => {
settings . open ( ) ;
settings . openTabById ( results . info ) ;
} ) ;
}
} ,
{
id : "BRAT-GrabBetaTheme" ,
icon : "BratIcon" ,
name : "Themes: Grab a beta theme for testing from a Github repository" ,
showInRibbon : true ,
callback : async ( ) => {
new AddNewTheme ( this . plugin ) . open ( ) ;
}
} ,
{
id : "BRAT-updateBetaThemes" ,
icon : "BratIcon" ,
name : "Themes: Update beta themes" ,
showInRibbon : true ,
callback : async ( ) => await themesCheckAndUpdates ( this . plugin , true )
} ,
{
id : "BRAT-allCommands" ,
icon : "BratIcon" ,
name : "All Commands list" ,
showInRibbon : false ,
callback : async ( ) => this . ribbonDisplayCommands ( )
}
] ;
this . plugin = plugin ;
this . bratCommands . forEach ( async ( item ) => {
this . plugin . addCommand ( {
id : item . id ,
name : item . name ,
icon : item . icon ,
callback : async ( ) => {
await item . callback ( ) ;
}
} ) ;
} ) ;
}
async ribbonDisplayCommands ( ) {
const bratCommandList = [ ] ;
this . bratCommands . forEach ( ( cmd ) => {
if ( cmd . showInRibbon )
bratCommandList . push ( { display : cmd . name , info : cmd . callback } ) ;
} ) ;
const gfs = new GenericFuzzySuggester ( this . plugin ) ;
const settings = this . plugin . app . setting ;
const listOfCoreSettingsTabs = Object . values ( settings . settingTabs ) . map ( ( t ) => {
return {
display : "Core: " + t . name ,
info : async ( ) => {
settings . open ( ) ;
settings . openTabById ( t . id ) ;
}
} ;
} ) ;
const listOfPluginSettingsTabs = Object . values ( settings . pluginTabs ) . map ( ( t ) => {
return {
display : "Plugin: " + t . name ,
info : async ( ) => {
settings . open ( ) ;
settings . openTabById ( t . id ) ;
}
} ;
} ) ;
bratCommandList . push ( { display : "---- Core Plugin Settings ----" , info : async ( ) => {
await this . ribbonDisplayCommands ( ) ;
} } ) ;
listOfCoreSettingsTabs . forEach ( ( si ) => bratCommandList . push ( si ) ) ;
bratCommandList . push ( { display : "---- Plugin Settings ----" , info : async ( ) => {
await this . ribbonDisplayCommands ( ) ;
} } ) ;
listOfPluginSettingsTabs . forEach ( ( si ) => bratCommandList . push ( si ) ) ;
gfs . setSuggesterData ( bratCommandList ) ;
await gfs . display ( async ( results ) => await results . info ( ) ) ;
}
} ;
// src/utils/BratAPI.ts
var BratAPI = class {
constructor ( plugin ) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
this . console = ( logDescription , ... outputs ) => {
console . log ( "BRAT: " + logDescription , outputs ) ;
} ;
this . themes = {
themeseCheckAndUpates : async ( showInfo ) => {
await themesCheckAndUpdates ( this . plugin , showInfo ) ;
} ,
themeInstallTheme : async ( cssGithubRepository ) => {
const scrubbedAddress = cssGithubRepository . replace ( "https://github.com/" , "" ) ;
await themeSave ( this . plugin , scrubbedAddress , true ) ;
} ,
themesDelete : async ( cssGithubRepository ) => {
const scrubbedAddress = cssGithubRepository . replace ( "https://github.com/" , "" ) ;
await themeDelete ( this . plugin , scrubbedAddress ) ;
} ,
grabCommmunityThemeCssFile : async ( repositoryPath , betaVersion = false ) => {
return await grabCommmunityThemeCssFile ( repositoryPath , betaVersion , this . plugin . settings . debuggingMode ) ;
} ,
grabChecksumOfThemeCssFile : async ( repositoryPath , betaVersion = false ) => {
return await grabChecksumOfThemeCssFile ( repositoryPath , betaVersion , this . plugin . settings . debuggingMode ) ;
} ,
grabLastCommitDateForAFile : async ( repositoryPath , path ) => {
return await grabLastCommitDateForAFile ( repositoryPath , path ) ;
}
} ;
this . plugin = plugin ;
}
} ;
// src/main.ts
var ThePlugin = class extends import _obsidian11 . Plugin {
constructor ( ) {
super ( ... arguments ) ;
this . appName = "Obsidian42 - Beta Reviewer's Auto-update Tool (BRAT)" ;
this . appID = "obsidian42-brat" ;
}
async onload ( ) {
console . log ( "loading Obsidian42 - BRAT" ) ;
await this . loadSettings ( ) ;
this . addSettingTab ( new BratSettingsTab ( this . app , this ) ) ;
this . betaPlugins = new BetaPlugins ( this ) ;
this . commands = new PluginCommands ( this ) ;
addIcons ( ) ;
if ( this . settings . ribbonIconEnabled )
this . showRibbonButton ( ) ;
this . app . workspace . onLayoutReady ( ( ) => {
if ( this . settings . updateAtStartup ) {
setTimeout ( async ( ) => {
await this . betaPlugins . checkForUpdatesAndInstallUpdates ( false ) ;
} , 6e4 ) ;
}
if ( this . settings . updateThemesAtStartup ) {
setTimeout ( async ( ) => {
await themesCheckAndUpdates ( this , false ) ;
} , 12e4 ) ;
}
setTimeout ( async ( ) => {
this . bratAPI = new BratAPI ( this ) ;
globalThis . bratAPI = this . bratAPI ;
} , 500 ) ;
} ) ;
}
showRibbonButton ( ) {
this . ribbonIcon = this . addRibbonIcon ( "BratIcon" , "BRAT" , async ( ) => this . commands . ribbonDisplayCommands ( ) ) ;
}
log ( textToLog , verbose = false ) {
logger ( this , textToLog , verbose ) ;
}
onunload ( ) {
console . log ( "unloading " + this . appName ) ;
}
async loadSettings ( ) {
this . settings = Object . assign ( { } , DEFAULT _SETTINGS , await this . loadData ( ) ) ;
}
async saveSettings ( ) {
await this . saveData ( this . settings ) ;
}
} ;
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vbm9kZV9tb2R1bGVzL29ic2lkaWFuLWRhaWx5LW5vdGVzLWludGVyZmFjZS9kaXN0L21haW4uanMiLCAiLi4vc3JjL21haW4udHMiLCAiLi4vc3JjL3VpL1NldHRpbmdzVGFiLnRzIiwgIi4uL3NyYy9mZWF0dXJlcy90aGVtZXMudHMiLCAiLi4vc3JjL2ZlYXR1cmVzL2dpdGh1YlV0aWxzLnRzIiwgIi4uL3NyYy91aS9zZXR0aW5ncy50cyIsICIuLi9zcmMvdXRpbHMvbm90aWZpY2F0aW9ucy50cyIsICIuLi9zcmMvdXRpbHMvaW50ZXJuZXRjb25uZWN0aW9uLnRzIiwgIi4uL3NyYy91aS9BZGROZXdUaGVtZS50cyIsICIuLi9zcmMvdWkvUHJvbW90aW9uYWwudHMiLCAiLi4vc3JjL3VpL0FkZE5ld1BsdWdpbk1vZGFsLnRzIiwgIi4uL3NyYy9mZWF0dXJlcy9CZXRhUGx1Z2lucy50cyIsICIuLi9zcmMvdWkvaWNvbnMudHMiLCAiLi4vc3JjL3V0aWxzL2xvZ2dpbmcudHMiLCAiLi4vc3JjL3VpL0dlbmVyaWNGdXp6eVN1Z2dlc3Rlci50cyIsICIuLi9zcmMvdWkvUGx1Z2luQ29tbWFuZHMudHMiLCAiLi4vc3JjL3V0aWxzL0JyYXRBUEkudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcblxudmFyIG9ic2lkaWFuID0gcmVxdWlyZSgnb2JzaWRpYW4nKTtcblxuY29uc3QgREVGQVVMVF9EQUlMWV9OT1RFX0ZPUk1BVCA9IFwiWVlZWS1NTS1ERFwiO1xuY29uc3QgREVGQVVMVF9XRUVLTFlfTk9URV9GT1JNQVQgPSBcImdnZ2ctW1ddd3dcIjtcbmNvbnN0IERFRkFVTFRfTU9OVEhMWV9OT1RFX0ZPUk1BVCA9IFwiWVlZWS1NTVwiO1xuY29uc3QgREVGQVVMVF9RVUFSVEVSTFlfTk9URV9GT1JNQVQgPSBcIllZWVktW1FdUVwiO1xuY29uc3QgREVGQVVMVF9ZRUFSTFlfTk9URV9GT1JNQVQgPSBcIllZWVlcIjtcblxuZnVuY3Rpb24gc2hvdWxkVXNlUGVyaW9kaWNOb3Rlc1NldHRpbmdzKHBlcmlvZGljaXR5KSB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICBjb25zdCBwZXJpb2RpY05vdGVzID0gd2luZG93LmFwcC5wbHVnaW5zLmdldFBsdWdpbihcInBlcmlvZGljLW5vdGVzXCIpO1xuICAgIHJldHVybiBwZXJpb2RpY05vdGVzICYmIHBlcmlvZGljTm90ZXMuc2V0dGluZ3M/LltwZXJpb2RpY2l0eV0/LmVuYWJsZWQ7XG59XG4vKipcbiAqIFJlYWQgdGhlIHVzZXIgc2V0dGluZ3MgZm9yIHRoZSBgZGFpbHktbm90ZXNgIHBsdWdpblxuICogdG8ga2VlcCBiZWhhdmlvciBvZiBjcmVhdGluZyBhIG5ldyBub3RlIGluLXN5bmMuXG4gKi9cbmZ1bmN0aW9uIGdldERhaWx5Tm90ZVNldHRpbmdzKCkge1xuICAgIHRyeSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZXhwbGljaXQtYW55XG4gICAgICAgIGNvbnN0IHsgaW50ZXJuYWxQbHVnaW5zLCBwbHVnaW5zIH0gPSB3aW5kb3cuYXBwO1xuICAgICAgICBpZiAoc2hvdWxkVXNlUGVyaW9kaWNOb3Rlc1NldHRpbmdzKFwiZGFpbHlcIikpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgZm9ybWF0LCBmb2xkZXIsIHRlbXBsYXRlIH0gPSBwbHVnaW5zLmdldFBsdWdpbihcInBlcmlvZGljLW5vdGVzXCIpPy5zZXR0aW5ncz8uZGFpbHkgfHwge307XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGZvcm1hdDogZm9ybWF0IHx8IERFRkFVTFRfREFJTFlfTk9URV9GT1JNQVQsXG4gICAgICAgICAgICAgICAgZm9sZGVyOiBmb2xkZXI/LnRyaW0oKSB8fCBcIlwiLFxuICAgICAgICAgICAgICAgIHRlbXBsYXRlOiB0ZW1wbGF0ZT8udHJpbSgpIHx8IFwiXCIsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgZm9sZGVyLCBmb3JtYXQsIHRlbXBsYXRlIH0gPSBpbnRlcm5hbFBsdWdpbnMuZ2V0UGx1Z2luQnlJZChcImRhaWx5LW5vdGVzXCIpPy5pbnN0YW5jZT8ub3B0aW9ucyB8fCB7fTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGZvcm1hdDogZm9ybWF0IHx8IERFRkFVTFRfREFJTFlfTk9URV9GT1JNQVQsXG4gICAgICAgICAgICBmb2xkZXI6IGZvbGRlcj8udHJpbSgpIHx8IFwiXCIsXG4gICAgICAgICAgICB0ZW1wbGF0ZTogdGVtcGxhdGU/LnRyaW0oKSB8fCBcIlwiLFxuICAgICAgICB9O1xuICAgIH1cbiAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIk5vIGN1c3RvbSBkYWlseSBub3RlIHNldHRpbmdzIGZvdW5kIVwiLCBlcnIpO1xuICAgIH1cbn1cbi8qKlxuICogUmVhZCB0aGUgdXNlciBzZXR0aW5ncyBmb3IgdGhlIGB3ZWVrbHktbm90ZXNgIHBsdWdpblxuICogdG8ga2VlcCBiZWhhdmlvciBvZiBjcmVhdGluZyBhIG5ldyBub3RlIGluLXN5bmMuXG4gKi9cbmZ1bmN0aW9uIGdldFdlZWtseU5vdGVTZXR0aW5ncygpIHtcbiAgICB0cnkge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWV4cGxpY2l0LWFueVxuICAgICAgICBjb25zdCBwbHVnaW5NYW5hZ2VyID0gd2luZG93LmFwcC5wbHVnaW5zO1xuICAgICAgICBjb25zdCBjYWxlbmRhclNldHRpbmdzID0gcGx1Z2luTWFuYWdlci5nZXRQbHVnaW4oXCJjYWxlbmRhclwiKT8ub3B0aW9ucztcbiAgICAgICAgY29uc3QgcGVyaW9kaWNOb3Rlc1NldHRpbmdzID0gcGx1Z2luTWFuYWdlci5nZXRQbHVnaW4oXCJwZXJpb2RpYy1ub3Rlc1wiKT8uc2V0dGluZ3M/LndlZWtseTtcbiAgICAgICAgaWYgKHNob3VsZFVzZVBlcmlvZGljTm90ZXNTZXR0aW5ncyhcIndlZWtseVwiKSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBmb3JtYXQ6IHBlcmlvZGljTm90ZXNTZXR0aW5ncy5mb3JtYXQgfHwgREVGQVVMVF9XRUVLTFlfTk9URV9GT1JNQVQsXG4gICAgICAgICAgICAgICAgZm9sZGVyOiBwZXJpb2RpY05vdGVzU2V0dGluZ3MuZm9sZGVyPy50cmltK