Last active
January 18, 2024 14:55
-
-
Save Shimilbi/b4558667432cfaa021242395557cc093 to your computer and use it in GitHub Desktop.
Open raw, and search for keywords.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { exec } from "child_process" | |
//#region ////////////////////////////////////////////////////// | |
//#region Exdending API objects with new functions inJS (different from Class oriented Language like C# and Java) | |
//#region In order to be able to call them as: type.function() instead of function(type) | |
// Only do this in small-team projects not to crowd the prototype node too much! | |
//#region ////////////////////////////////////////////////////// | |
// Extension functions (easier to do with Typescript thanks to the declare and interface statments) | |
// Note: "global" interfaces and functions are automatically exported, no need to add "export" | |
declare global { | |
interface Array<T> { | |
ReplaceEntry<T>(): boolean // not yet defined | |
} | |
interface Object { | |
implementOf<Interface>(): boolean | |
} | |
interface String { | |
getWorkingDirectory(): string | |
getFileName(): string | |
getExtension(): string | |
textToHTMLDocumentObject(): any | |
startsWithEither(...cues:string[]): boolean | |
endsWithEither(...cues:string[]): boolean | |
includesEither(...cues:string[]): boolean | |
remove(oldString:string): string | |
removeAll(oldString:string): string | |
removeLast(oldString:string): string | |
replaceAll(oldString:string, newString:string): string | |
replaceLast(oldString:string, newString:string): string | |
} | |
interface Date { | |
toUTC(): Date | |
getLapseSince(laterDate:Date): number | |
} | |
interface Map<K,V> { | |
hasValue<V>(value:V): boolean //DONE | |
valuesToArray(): V[] //DONE | |
keysToArray(): K[] //DONE | |
getFirst(): V //DONE | |
getLast(): V //DONE | |
getPrevious<K>(currentKey:K): V //DONE | |
getNext<K>(currentKey:K): V //DONE | |
firstKey(): K | |
lastKey(): K | |
previousKey<K>(currentKey:K): K //DONE | |
nextKey<K>(currentKey:K): K //DONE | |
indexOfKey(key:K): number //DONE | |
getByIndex(i:number): V //DONE | |
filter<K,V>(predicate: (entry:[K,V], index?:number) => unknown): Map<K,V> //DONE? | |
getPromiseResults<Promise, T>(): T //DONE | |
} | |
} | |
//#region New funcitons extending the objects | |
Map.prototype.hasValue = function<V>(value:V) { | |
for (let [k, v] of this) | |
if (v===value) return true | |
return false | |
} | |
Map.prototype.valuesToArray = function<V>() { | |
return [...this.values()] | |
} | |
Map.prototype.keysToArray = function<K>() { | |
return [...this.keys()] | |
} | |
Map.prototype.getFirst = function() { | |
return [...this.values()][0] | |
} | |
Map.prototype.getLast = function() { | |
const asArray = [...this.values()] | |
return asArray[asArray.length-1] | |
} | |
Map.prototype.getPrevious = function<K>(currentKey:K) { | |
const asArray = [...this.entries()] | |
const i = asArray.indexOf(this.get(currentKey)) | |
return asArray[i-1] | |
} | |
Map.prototype.getNext = function<K>(currentKey:K) { | |
const asArray = [...this.entries()] | |
const i = asArray.indexOf(this.get(currentKey)) | |
return asArray[i+1] | |
} | |
Map.prototype.firstKey = function() { | |
return [...this.keys()][0] | |
} | |
Map.prototype.lastKey = function() { | |
const asKeyArray = [...this.keys()] | |
return asKeyArray[asKeyArray.length-1] | |
} | |
Map.prototype.previousKey = function<K>(currentKey:K) { | |
const asKeyArray = [...this.keys()] | |
const i = asKeyArray.indexOf(this.get(currentKey)) | |
return asKeyArray[i-1] | |
} | |
Map.prototype.nextKey = function<K>(currentKey:K) { | |
const asKeyArray = [...this.keys()] | |
const i = asKeyArray.indexOf(this.get(currentKey)) | |
return asKeyArray[i+1] | |
} | |
Map.prototype.indexOfKey = function<K>(key:K) { | |
const asArray = [...this.values()] | |
return asArray.indexOf(this.get(key)) | |
} | |
Map.prototype.getByIndex = function(i:number) { | |
const asArray = [...this.values()] | |
return asArray[i] | |
} | |
String.prototype.getWorkingDirectory = function () { | |
if (!IsValidUrl(this as string)) throw "(" + this + "is not an exiting url.)" | |
const tempPathCopy = this as string | |
tempPathCopy.split("/").pop() | |
return tempPathCopy | |
} | |
String.prototype.getFileName = function () { | |
if (!IsValidUrl(this as string)) throw "(" + this as string + "is not an exiting url.)" | |
const tempPathCopy = this as string | |
return tempPathCopy.split("/").pop()! | |
} | |
String.prototype.getExtension = function () { | |
const temp = this! as string | |
return "." + temp.split('.').pop() | |
} | |
/** Deletes all occurence of a substring in a string, and returns the result */ | |
String.prototype.removeAll = function (oldString) { | |
if (!this.includes(oldString)) return this.toString() | |
return this.split(oldString).join("").toString() | |
} | |
/** Deletes the fist occurence of a substring in a string, and returns the result */ | |
String.prototype.remove = function (oldString) { | |
if (!this.includes(oldString)) return this.toString() | |
let pieces = this.split(oldString) | |
pieces.shift() | |
return pieces.join(oldString).toString() | |
} | |
/** Deletes the last occurence of a substring in a string, and returns the result */ | |
String.prototype.removeLast = function (oldString) { | |
if (!this.includes(oldString)) return this.toString() | |
let pieces = this.split(oldString) | |
pieces.pop() | |
return pieces.join(oldString).toString() | |
} | |
/** Replaces all occurence of a substring in a string, and returns the result */ | |
String.prototype.replaceAll = function (oldString, newString) { | |
if (!this.includes(oldString.toString())) return this.toString() | |
return this.split(oldString).join(newString.toString()) | |
} | |
/** Replaces the last occurence of a substring in a string, and returns the result */ | |
String.prototype.replaceLast = function (oldString, newString) { | |
if (!this.includes(oldString)) return this.toString() | |
let pieces = this.split(oldString) | |
pieces.pop() | |
return (pieces.join(oldString) + newString).toString() | |
} | |
String.prototype.startsWithEither = function(...cues:string[]) { | |
return cues.some(cue => this.trim().toLowerCase().startsWith(cue.trim().toLowerCase())) | |
} | |
String.prototype.endsWithEither = function(...cues:string[]) { | |
return cues.some(cue => this.trim().toLowerCase().endsWith(cue.trim().toLowerCase())) | |
} | |
String.prototype.includesEither = function(...cues:string[]) { | |
return cues.some(cue => this.trim().toLowerCase().includes(cue.trim().toLowerCase())) | |
} | |
Date.prototype.toUTC = function() { | |
// Returns a Date: YYYY-MM-DD HH-MM-SS UTC | |
return new Date(this.getUTCFullYear(), this.getUTCMonth(), this.getUTCDay(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()) | |
} | |
//#region Other functions | |
export const DateNow_asUTC = () => | |
new Date(Date.now()).toUTC() | |
/** Format: YYYY_MM_DD_HH_MM_SS */ | |
export const DateNow_asUTCstring = () => | |
DateNow_asUTC().toUTCString() | |
export class Randomizer<T> { | |
Pool :T[] | |
UsedEntries? :T[] | |
LastPick? :T | |
DebugErrorTolerence :number = 5 | |
constructor(...list:T[]) { | |
this.Pool = list as T[] | |
// console.log("\n(F.Randomizer: Pool is: " + this.PoolOfUnused().join("|")+" )") | |
} | |
// Optional call | |
#Cheat (edgeTowardThisValue:T) { | |
if (this.LastPick===undefined) | |
throw "(Randomizer.#Cheat: Please first get a random pick before cheating on it.)" | |
const remnents = this.PoolOfUnused() | |
if (!remnents.includes(this.LastPick)) | |
throw "(Randomizer.#Cheat: Please don't eliminate the initial random pick before cheating on it.)" | |
let pickedIndex = remnents.includes(this.LastPick) | |
? remnents.indexOf(this.LastPick) | |
: this.Pool.indexOf(this.LastPick) | |
// console.log("Randomizer.#Cheat (DEBUG) of index "+pickedIndex) | |
let indexToEdgeTowardOf = remnents.indexOf(edgeTowardThisValue) | |
// console.log("edgeTowardThisValue="+edgeTowardThisValue) | |
if (indexToEdgeTowardOf > pickedIndex && pickedIndex < remnents.length-1) pickedIndex += 1 | |
else if (indexToEdgeTowardOf < pickedIndex && pickedIndex > 0) pickedIndex -= 1 | |
// console.log("index changed for "+pickedIndex) | |
this.LastPick = remnents[pickedIndex] | |
// console.log("favored value: "+this.LastPick) | |
return this | |
} | |
// Optional call | |
#ThenEliminate () { | |
if (this.LastPick===undefined) | |
throw "(Randomizer.#ThenEliminate: Please first get a random pick, then eventually cheat about it, before eliminating it.)" | |
this.UsedEntries ??= [] | |
this.UsedEntries.push(this.LastPick) | |
if (this.UsedEntries.length>0) | |
// If all values were picked once, All are available again | |
if (this.UsedEntries.every(usedEntry => | |
this.PoolOfUnused().includes(usedEntry)) | |
) | |
this.UsedEntries = [] | |
return this | |
} | |
PoolOfUnused() { | |
if (this.UsedEntries===undefined||this.UsedEntries?.length<1) | |
return this.Pool | |
else { | |
let unused: T[] = this.Pool.filter(entry => !this.UsedEntries!.includes(entry)) | |
return unused.length < 1 ? this.Pool : unused | |
} | |
} | |
getRandom(avoidDuplicates?:boolean, entryToFavor?:T) { | |
const remnants = this.PoolOfUnused() | |
// console.log("(Randomizer.GetRandom (DEBUG) Pool: \n- "+remnants.join("\n- ")) | |
this.LastPick = remnants.length==1 | |
? remnants[0] | |
: remnants[Math.floor( (Math.random() * remnants.length) + 1 )] | |
// console.log("> "+this.LastPick+" <") | |
if (this.LastPick===undefined && this.DebugErrorTolerence>0) { | |
this.DebugErrorTolerence-=1 | |
console.log("(repicking)") | |
this.getRandom() | |
} | |
else if (this.LastPick===undefined && this.DebugErrorTolerence==0) { | |
this.LastPick = remnants[0] | |
// throw "A random result could not be picked (and present function might have been looping endlessly by now, so recursivity was limited to 5 consecutive times.)\nWhy are there erros? Maybe because the core function (not my own code) is bugged." | |
} | |
const hasFavorite = entryToFavor!==undefined | |
if (hasFavorite) this.#Cheat(entryToFavor) | |
if (avoidDuplicates) this.#ThenEliminate() | |
return this.LastPick | |
} | |
} | |
export const ExecuteInTerminal = (nodeJsCommandLine: string) => { | |
exec(nodeJsCommandLine, (error, stdout, stderr) => { | |
if (error) { | |
console.log(`error: ${error.message}`) | |
return | |
} | |
if (stderr) { | |
console.log(`stderr: ${stderr}`) | |
return | |
} | |
console.log(`stdout: ${stdout}`) | |
}) | |
} | |
const ConvertMsTo = { | |
secs: (timestamp_in_milliseconds:number) => { | |
const aSecInMs = 1000 | |
return laterDate.getLapseSince(timestamp_in_milliseconds) / aSecInMs | |
}, | |
mins: (timestamp_in_milliseconds:number) => { | |
const aMinInMs = 1000 * 60 | |
return laterDate.getLapseSince(timestamp_in_milliseconds) / aMinInMs | |
}, | |
hours: (timestamp_in_milliseconds:number) => { | |
const anHourInMs = 1000 * 60 * 60 | |
return laterDate.getLapseSince(timestamp_in_milliseconds) / anHourInMs | |
}, | |
days: (timestamp_in_milliseconds:number) => { | |
const aDayInMs = 1000 * 60 * 60 * 24 | |
return laterDate.getLapseSince(timestamp_in_milliseconds) / aDayInMs | |
} | |
} | |
export var always_varying_value: symbol = Symbol() | |
export const IsValidUrl = (url:string) => { | |
try { | |
return Boolean(new URL(url)) | |
} | |
catch(e){ | |
return false | |
} | |
} | |
/** | |
* SUPER PRECIOUS! | |
GENERATES A DOM in an environment where the browser is availiable but it's not possible to write on the webpage! | |
GENERATES A DOM from a string, without writing a file on any drive! | |
So that we can use the tools of that interface, such as filepicker, textarea for linbreak supported copying, page formatting, etc. | |
* How to use: | |
const storedHtml = '<html><body></body></html>' | |
const doc = storedHtml.textToHTMLdocument() | |
*/ | |
String.prototype.textToHTMLDocumentObject = function () { | |
let parseXml: (xmlStr: String) => any | |
if (globalThis.DOMParser) | |
parseXml = function(xmlStr:String) { | |
return ( new globalThis.DOMParser() ).parseFromString(xmlStr, "text/xml") | |
} | |
else if (typeof globalThis.ActiveXObject != "undefined" && new globalThis.ActiveXObject("Microsoft.XMLDOM")) | |
parseXml = function(xmlStr:String) { | |
let xmlDoc = new globalThis.ActiveXObject("Microsoft.XMLDOM") | |
xmlDoc.async = "false" | |
xmlDoc.loadXML(xmlStr) | |
return xmlDoc | |
} | |
else | |
throw this+"\n could not be converted into a HTMLDocument." | |
return parseXml(this).implementation.createHTMLDocument() | |
} | |
//#region Ranges | |
export class Range { | |
Min: number | |
Max: number | |
AllowedValues: number[] | |
Field: number | |
constructor(min_: number|string, max_: number, field_: number) { | |
this.Min = min_==="unlimited" && max_===undefined? 0 : (min_ as number) | |
this.Max = min_==="unlimited" && max_===undefined? 999999999999999 : max_ | |
this.AllowedValues = [this.Min] | |
for (let i = this.Min; i <= this.Max; i++) | |
this.AllowedValues.push(i) | |
if (!this.AllowedValues.includes(field_)) | |
throw "Can't create range of ("+this.Min+"-"+this.Max+"), because default value " +field_+ " is out of range." | |
this.Field = field_ | |
} | |
canIncrement (step_?: number) { | |
let step = step_ ?? 1 | |
return this.Field + step <= this.Max | |
} | |
increment (step_?: number) { | |
let step = step_ ?? 1 | |
if (this.Field + step>this.Max) | |
console.log("Range.OperateWithinRange: " + this.Field + " would exceed the maximum of " + this.Max) | |
else | |
return this.Field += step as number | |
} | |
canDecrement (step_?: number) { | |
let step = step_ ?? 1 | |
return this.Field - step >= (this.Min as number) | |
} | |
decrement (step_?: number) { | |
let step = step_ ?? 1 | |
if (this.Field - step<(this.Min as number)) | |
console.log("Range.OperateWithinRange: " + this.Field + " would be below the minimum of " + this.Max) | |
else | |
return this.Field -= step as number | |
} | |
IsWithinRange (value_: number) { | |
return this.AllowedValues.includes(value_) | |
} | |
override (newValue_: number) { | |
if (!this.IsWithinRange(newValue_)) | |
throw "Range.OperateWithinRange: " + newValue_ + " is not within authorised range of (" + this.Min + ", " + this.Max + ")" | |
return this.Field = newValue_ | |
} | |
tryOverride (newValue_: number) { | |
return this.Field = this.IsWithinRange(newValue_) ? newValue_ : this.Field | |
} | |
} | |
// To use vales as a ts type in order to limite allowed values | |
export const MetaMetaGenerateRangeOfValues = ()=> { | |
// Generates A Range Of Values In The Terminal, For The Unique Purpose Of Copy-Pasting It In The Code | |
const Range = (min: number, max: number, step_?: number) => { | |
const step = step_ ??= 1 | |
Array.from( new Array( max > min ? Math.ceil((max - min)/step) : Math.ceil((min - max)/step) ), ( x, i ) => max > min ? i*step + min : min - i*step ).join(" | ") | |
} | |
console.log(Range(3,10)) | |
// Note: the function itself won't be accepted by typescript as a valid value. | |
// must use the console.log and copy paste it as a value in the typescript code hre | |
} | |
export async function GetOuterJson_Content(url = "", asJson?:boolean) { // but doesn't copy/import it in website deploy | |
const response = await fetch(url, { | |
method: "GET", | |
mode: "cors", // no-cors, *cors, same-origin | |
credentials: "same-origin", // include, *same-origin, omit | |
headers: {"Content-Type": "application/json"} | |
}) | |
return JSON.parse(await response.json() as any) as { [key: string]:any } | |
} | |
export async function GetOuterFile_Content(url = "") { // but doesn't copy/import it in website deploy | |
const response = await fetch(url) | |
return await (response.text()) as string | |
} | |
export async function PostIntoGlobalDATABASE(key:string, newValue:string) { | |
const url = "" | |
const newObj:{ [key: string]:any } = await GetOuterJson_Content(url, true) as { [key: string]:any } | |
newObj[key] = newValue | |
const response = await fetch(url, { | |
method: "POST", // *GET, POST, PUT, DELETE, etc. | |
mode: "cors", // no-cors, *cors, same-origin | |
credentials: "same-origin", // include, *same-origin, omit | |
headers: { | |
"Content-Type": "application/json", | |
// 'Content-Type': 'application/x-www-form-urlencoded', | |
}, | |
redirect: "follow", // manual, *follow, error | |
referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url | |
body: JSON.stringify(newObj) // le type utilisé pour le corps doit correspondre à l'en-tête "Content-Type" | |
}) | |
return response.json() // transforme la réponse JSON reçue en objet JavaScript natif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment