Initial Commit
This commit is contained in:
39
public/js-source/.eslintrc.js
Normal file
39
public/js-source/.eslintrc.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// eslint-disable-next-line no-undef
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: '@typescript-eslint/parser',
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
'no-null',
|
||||
],
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
],
|
||||
rules: {
|
||||
"no-console": "error",
|
||||
"max-len": ["error", {"code": 128}],
|
||||
"no-process-env": "error",
|
||||
"no-process-exit": "error",
|
||||
"no-null/no-null": "error",
|
||||
"no-useless-return": "error",
|
||||
"prefer-arrow-callback": "warn",
|
||||
"object-curly-spacing": "error",
|
||||
"consistent-return": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": [
|
||||
"error", {
|
||||
"allowExpressions": true,
|
||||
},
|
||||
],
|
||||
"no-void": "error",
|
||||
"comma-spacing": "error",
|
||||
"comma-dangle": ["error", "always-multiline"],
|
||||
|
||||
"no-restricted-imports": ["error",
|
||||
"assert", "buffer", "child_process", "cluster", "crypto", "dgram", "dns", "domain", "events", "freelist",
|
||||
"fs", "http", "https", "module", "net", "os", "path", "punycode", "querystring", "readline", "repl",
|
||||
"smalloc", "stream", "string_decoder", "sys", "timers", "tls", "tracing", "tty", "url", "util", "vm", "zlib",
|
||||
],
|
||||
},
|
||||
};
|
||||
7
public/js-source/src/SomeModule.ts
Normal file
7
public/js-source/src/SomeModule.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import {getUserInfo} from './utils';
|
||||
|
||||
export async function getUserName(): Promise<string> {
|
||||
const info = await getUserInfo();
|
||||
return info?.name ?? "No name found!";
|
||||
}
|
||||
|
||||
12
public/js-source/src/index.ts
Normal file
12
public/js-source/src/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
// Export setConfig so that the external url can set set automatically
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export {setConfig} from './utils';
|
||||
|
||||
import {getUserName} from './SomeModule';
|
||||
|
||||
getUserName().then((name) => {
|
||||
const node = document.createElement('span');
|
||||
node.innerText = `This user name is fetched with Javascript: ${name}`;
|
||||
document.getElementsByTagName("body")[0].appendChild(node);
|
||||
});
|
||||
78
public/js-source/src/resolvable.ts
Normal file
78
public/js-source/src/resolvable.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
enum ResolvableState {
|
||||
WAITING,
|
||||
PENDING,
|
||||
ERROR,
|
||||
DONE
|
||||
}
|
||||
|
||||
class FetchOnce<T> {
|
||||
protected data: T|undefined;
|
||||
protected error: unknown|undefined;
|
||||
protected state: ResolvableState = ResolvableState.WAITING;
|
||||
protected pendings: [(res: Promise<T>|T) => void, (reason: unknown) => void][] = [];
|
||||
|
||||
constructor(protected fetchMethod?: () => Promise<T>) { }
|
||||
|
||||
public resolve(): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
switch (this.state) {
|
||||
case ResolvableState.WAITING:
|
||||
this.state = ResolvableState.PENDING;
|
||||
this.pendings.push([resolve, reject]);
|
||||
if (this.fetchMethod) this.parsePromise(this.fetchMethod());
|
||||
break;
|
||||
case ResolvableState.PENDING:
|
||||
this.pendings.push([resolve, reject]);
|
||||
break;
|
||||
case ResolvableState.DONE:
|
||||
resolve(this.data);
|
||||
break;
|
||||
case ResolvableState.ERROR:
|
||||
reject(this.error);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected isFinished(): boolean {
|
||||
return this.state === ResolvableState.DONE || this.state === ResolvableState.ERROR;
|
||||
}
|
||||
|
||||
protected parsePromise(promise: Promise<T>): void {
|
||||
promise.then((data) => {
|
||||
this.data = data;
|
||||
this.state = ResolvableState.DONE;
|
||||
this.pendings.forEach(pending => pending[0](data));
|
||||
}).catch(err => {
|
||||
this.error = err;
|
||||
this.state = ResolvableState.ERROR;
|
||||
this.pendings.forEach(pending => pending[1](err));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Resolvable<T> extends FetchOnce<T> {
|
||||
constructor(fetchMethod: () => Promise<T>) {
|
||||
super(fetchMethod);
|
||||
}
|
||||
}
|
||||
|
||||
export class WaitForSync<T> extends FetchOnce<T> {
|
||||
protected state: ResolvableState = ResolvableState.PENDING;
|
||||
|
||||
constructor() {
|
||||
super(undefined);
|
||||
}
|
||||
|
||||
public setData(data: T): void {
|
||||
if (!this.isFinished()) {
|
||||
this.parsePromise((async () => data)());
|
||||
}
|
||||
}
|
||||
|
||||
public setError(error: unknown): void {
|
||||
if (!this.isFinished()) {
|
||||
this.parsePromise((async () => { throw error; })());
|
||||
}
|
||||
}
|
||||
}
|
||||
10
public/js-source/src/types/userinfo.d.ts
vendored
Normal file
10
public/js-source/src/types/userinfo.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
type UserInfo = {
|
||||
email: string,
|
||||
email_verified: boolean,
|
||||
family_name: string,
|
||||
given_name: string,
|
||||
groups: string[],
|
||||
name: string,
|
||||
preferred_username: string,
|
||||
sub: string,
|
||||
};
|
||||
23
public/js-source/src/utils.ts
Normal file
23
public/js-source/src/utils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import {WaitForSync} from './resolvable';
|
||||
|
||||
export interface ClientConfig {
|
||||
EXTERNAL_BASE_URL: string
|
||||
}
|
||||
|
||||
let config: ClientConfig|undefined;
|
||||
const configWaiter = new WaitForSync<ClientConfig>();
|
||||
|
||||
export function setConfig(clientConfig: ClientConfig): void {
|
||||
config = clientConfig;
|
||||
configWaiter.setData(config);
|
||||
}
|
||||
|
||||
export function getConfig(): Promise<ClientConfig> {
|
||||
return configWaiter.resolve();
|
||||
}
|
||||
|
||||
export async function getUserInfo(): Promise<UserInfo|undefined> {
|
||||
const getBaseUrl = await getConfig();
|
||||
const res = await fetch(getBaseUrl.EXTERNAL_BASE_URL + "/api/user");
|
||||
return res.json();
|
||||
}
|
||||
23
public/js-source/tsconfig.json
Normal file
23
public/js-source/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "amd",
|
||||
"lib": ["es5", "es6", "dom"],
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"outFile": "../js/bundle.js",
|
||||
"target": "es5",
|
||||
"sourceMap": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": true,
|
||||
"strict": true,
|
||||
"sourceRoot": "./src",
|
||||
"rootDir": ".",
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": "."
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user