Last active
April 20, 2023 09:04
-
-
Save sebilasse/98aa5e5fa6718e5443cbe0d02e2e27eb to your computer and use it in GitHub Desktop.
@Jsonld (decorators)
This file contains 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 { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts"; | |
import { crypto } from "https://deno.land/std@0.182.0/crypto/mod.ts"; | |
import * as log from "https://deno.land/std@0.182.0/log/mod.ts"; | |
import defaultContext, { transportInsecure } from "/protocol/default.ts"; | |
import prefixes from "/redaktor/known/prefixes.ts"; | |
import equalsPrimitives from "objectIsEqualPrimitivesShallow"; | |
import normal from "objectNormal"; | |
import jsonld from "jsonld"; | |
import { toArray } from "to"; | |
export async function compact(doc: string | {[k: string]: any}, ctx: string | {[k: string]: any}) { | |
if (typeof doc === "string" && doc.trim().charAt(0) === "{") doc = JSON.parse(doc); | |
if (typeof ctx === "string" && ctx.trim().charAt(0) === "{") ctx = JSON.parse(ctx); | |
return jsonld.compact(doc, ctx); | |
} | |
export async function expand(doc: string | {[k: string]: any}) { | |
if (typeof doc === "string" && doc.trim().charAt(0) === "{") doc = JSON.parse(doc); | |
return jsonld.expand(doc); | |
} | |
/* JSON LD Decorators */ | |
const CONTEXT$ = Symbol.for('redaktor@context'); | |
const PREFIX$ = Symbol.for('redaktor@prefix'); | |
const SCHEMA$ = Symbol.for('redaktor@schema'); | |
const FUNCTIONAL = "owl:FunctionalProperty"; | |
const DATATYPE = "owl:DatatypeProperty"; | |
const SHORTCUTS = { | |
"@id": "@id", | |
"@index": "@index", | |
"@graph": "@graph", | |
"@language": "@language", | |
"@list": "@list", | |
"@set": "@set", | |
"@type": "@type" | |
} | |
const C = { | |
id: "@id", | |
index: "@index", | |
graph: "@graph", | |
language: "@language", | |
list: "@list", | |
set: "@set", | |
type: "@type" | |
} | |
const D = { | |
string: "xsd:string", | |
id: "@id", | |
json: "@json", | |
uri: "xsd:anyURI", | |
token: "xsd:token", | |
set: "@set", | |
boolean: "xsd:boolean", | |
decimal: "xsd:decimal", | |
int: "xsd:int", | |
intPositive: "xsd:nonNegativeInteger", | |
/* TODO xsd:dateTime also DtoSchema | |
https://www.w3.org/TR/activitystreams-core/#dates | |
as2-partial-time = time-hour ":" time-minute [":" time-second] | |
[time-secfrac] | |
as2-full-time = as2-partial-time time-offset | |
as2-date-time = full-date "T" as2-full-time | |
TODO "title" and "description" from TSDOC or wdt: ? | |
https://json-schema.org/draft/2020-12/json-schema-validation.html#name-title-and-description | |
+ "default", "deprecated", "readOnly" and "writeOnly", "examples" | |
TODO custom err message via decorator | |
*/ | |
} | |
const P = { | |
/** Activity Vocabulary - W3C Rec. */ | |
as: prefixes.as, | |
/** The Schema.org vocabulary */ | |
schema: prefixes.schema, | |
/** wikidata */ | |
wd: prefixes.wd, | |
wdt: prefixes.wdt, | |
/** XML Schema Datatypes, XML Schema Part 2: Datatypes Second Edition - W3C Rec. */ | |
xsd: prefixes.xsd | |
} | |
const DtoSchema = { | |
"xsd:string": { type: "string" }, | |
"@id": { type: "string", format: "iri" }, | |
"@json": { type: "string", format: "redaktor-json" }, | |
"xsd:anyURI": { type: "string", format: "uri" }, | |
"xsd:token": { type: "string" }, | |
"@set": { type: "array" }, | |
"xsd:boolean": { type: "boolean" }, | |
"xsd:decimal": { type: "number" }, | |
"xsd:int": { type: "integer" }, | |
"xsd:nonNegativeInteger": { type: "integer", exclusiveMinimum: 0 } | |
} | |
type ContainerType = string & Function; | |
type ContainerTypes = { | |
set: ContainerType, list: ContainerType, graph: ContainerType, | |
id: ContainerType, index: ContainerType, language: ContainerType, | |
idMap: ContainerType, indexMap: ContainerType, languageMap: ContainerType, typeMap: ContainerType | |
}; | |
const CACHE = {}; | |
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x); | |
const targetIds = (fn: Function|FunctionConstructor, key?: string) => fn.toString().split("{")[0] | |
.replace(/(^class )|( extends )/g, " ").trim().split(" ") | |
.map((s, i) => `redaktor.${s.trim()}`); | |
const targetType = (tstrType: any) => { | |
if (tstrType === String) { | |
return D.string | |
} else if (tstrType === Number) { | |
return D.decimal | |
} else if (tstrType === Boolean) { | |
return D.boolean | |
} else if (tstrType === Object) { | |
return "owl:ObjectProperty" | |
} | |
} | |
let curSchema: {format?: string[]} & {[k:string]: number|string|(number|string)[]} = {}; | |
const setCacheGetId = (constructor: any, key: string) => { | |
const tId = targetIds(constructor)[0]; | |
if (!CACHE[tId]) curSchema = {}; | |
if (!CACHE[tId]) Object.assign(CACHE, {[tId]: { [CONTEXT$]: {"@version": 1.1}, [PREFIX$]: P }}); | |
if (!CACHE[tId][CONTEXT$][key]) { | |
Object.assign(CACHE[tId][CONTEXT$], { | |
[key]: { id: "", container: [], protected: false, type: { ts: [], ld: [] }, schema: {} } | |
}); | |
} | |
return tId; | |
} | |
const checkPrefixOrUrl = (s: string, key: string, ctxPrefixes: {[k: string]: string} = {}): boolean => { | |
if (SHORTCUTS[s] || key.indexOf(":@") > 0) return true; | |
if (s.indexOf(":") > -1) { | |
const [prefix, vId] = s.split(":"); | |
if (!transportInsecure[prefix] && !P[prefix] && !ctxPrefixes[prefix]) { | |
// prefix not found | |
return false; | |
} | |
} else { | |
log.warning(`${key}: No protocol or prefix`); | |
log.warning(`This is not an URI and could not be expanded to an URI. | |
It will be treated as plain JSON ...`); | |
return false; | |
} | |
return true; | |
} | |
const jsonschemaFromContext = (ctx: any) => { | |
} | |
export function protectFn(target: any, key: string) { | |
const t = Reflect.getMetadata("design:type", target, key); | |
const tId = setCacheGetId(target.constructor, key); | |
CACHE[tId][CONTEXT$][key].protected = true; | |
} | |
export const protect: Function = protectFn; | |
export function type(ld: string | string[] = D.id, cType: string | string[] = [], jsonSchema?: any): Function { | |
return function (target: any, key: string) { | |
const tId = setCacheGetId(target.constructor, key); | |
CACHE[tId][CONTEXT$][key].type.ld = ld; | |
if (jsonSchema) CACHE[tId][CONTEXT$][key].schema = jsonSchema; | |
const cTypes = toArray(cType); | |
if (cTypes.length) { | |
CACHE[tId][CONTEXT$][key].container = CACHE[tId][CONTEXT$][key].container | |
.concat(cTypes); | |
Reflect.defineMetadata("type-decorator", cType, target, key); | |
} | |
// console.log("2 @type", ld, tId, ":", key); | |
Reflect.defineMetadata("type-decorator", ld, target, key); | |
} | |
} | |
export function container(cType: string | string[] | false = C.set, idStr?: string): Function { | |
return function (target: any, key: string) { | |
const cTypes = toArray(cType); | |
const tId = setCacheGetId(target.constructor, key); | |
if (!cType) { | |
CACHE[tId][CONTEXT$][key].container = false; | |
Reflect.defineMetadata("container-decorator", false, target, key); | |
return; | |
} | |
CACHE[tId][CONTEXT$][key].container = CACHE[tId][CONTEXT$][key].container | |
.concat(cTypes); | |
// console.log("2 @type", ld, tId, ":", key); | |
Reflect.defineMetadata("container-decorator", cTypes, target, key); | |
if (idStr) id(idStr)(target, key); | |
}; | |
} | |
/* TODO | |
// ["@graph", "@index"] | |
// ["@graph", "@id"] | |
*/ | |
container.set = container(C.set); | |
container.list = container(C.list); | |
container.graph = container(C.graph); | |
container.id = container(C.id); | |
container.index = container(C.index); | |
container.language = container(C.language); | |
container.idMap = container([C.id, C.set]); | |
container.indexMap = container([C.index, C.set]); | |
container.languageMap = container([C.language, C.set]); | |
container.typeMap = container([C.type, C.set]); | |
export function id(id: string): Function & ContainerTypes { | |
console.log(id); | |
const idFn = function (target: any, key: string) { | |
console.log("1 @id", key); | |
const t = Reflect.getMetadata("design:type", target, key); | |
const tId = setCacheGetId(target.constructor, key); | |
const [prefix, vId] = id.split(":"); | |
if (prefix && vId && !CACHE[tId][PREFIX$][prefix]) { | |
CACHE[tId][PREFIX$][prefix] = prefixes[prefix] ? prefixes[prefix] : ""; | |
} | |
if (CACHE[tId][CONTEXT$][key].id && CACHE[tId][CONTEXT$][key].id !== id) { | |
log.warning(`${tId}: JSON-LD context: Key already defined`); | |
log.warning(`The key ${key} was already defined as ${CACHE[tId][CONTEXT$][key].id}. | |
It will be overwritten as ${id} ...`); | |
} | |
CACHE[tId][CONTEXT$][key].id = id; | |
CACHE[tId][CONTEXT$][key].type.ts = targetType(t); | |
console.log("2 @id", id, target, ":", key); | |
Reflect.defineMetadata("id-decorator", id, target, key); | |
}; | |
idFn.set = Object.assign(container(C.set, id), idFn); | |
idFn.list = Object.assign(container(C.list, id), idFn); | |
idFn.graph = Object.assign(container(C.graph, id), idFn); | |
idFn.id = Object.assign(container(C.id, id), idFn); | |
idFn.index = Object.assign(container(C.index, id), idFn); | |
idFn.language = Object.assign(container(C.language, id), idFn); | |
idFn.idMap = Object.assign(container([C.id, C.set], id), idFn); | |
idFn.indexMap = Object.assign(container([C.index, C.set], id), idFn); | |
idFn.languageMap = Object.assign(container([C.language, C.set], id), idFn); | |
idFn.typeMap = Object.assign(container([C.type, C.set], id), idFn); | |
return idFn as any | |
} | |
export type Constructor = { | |
new (...args: any[]): {} | |
prototype: any; | |
name: string; | |
} | |
export function context(contextPrefix: string, customPrefixes = {}): Function { | |
return function <T extends { new (...args: any[]): {} }>(constructor: T): T | void { | |
const targets = targetIds(constructor); | |
const tId = targets[0]; | |
const ctxPrefixes = {}; | |
CACHE[tId][PREFIX$][contextPrefix] = ""; | |
for (const k in JSON.parse(JSON.stringify(CACHE[tId][PREFIX$]))) { | |
if (CACHE[tId][PREFIX$][k]) { | |
ctxPrefixes[k] = CACHE[tId][PREFIX$][k]; | |
continue; | |
} | |
if (customPrefixes[k]) { | |
ctxPrefixes[k] = customPrefixes[k]; | |
continue; | |
} | |
if (prefixes[k]) { | |
ctxPrefixes[k] = prefixes[k]; | |
continue; | |
} | |
} | |
for (const k in CACHE[tId][CONTEXT$]) { | |
if (k.charAt(0) === "@" || !CACHE[tId][CONTEXT$][k] || !CACHE[tId][CONTEXT$][k].type) continue; | |
const _type = CACHE[tId][CONTEXT$][k].type.ld.length | |
? CACHE[tId][CONTEXT$][k].type.ld | |
: CACHE[tId][CONTEXT$][k].type.ts; | |
// TODO CACHE[tId][CONTEXT$][k].schema console.log("SET",jsonSchema,tId,k,CACHE[tId][CONTEXT$][k]) | |
if (!CACHE[tId][CONTEXT$][k].schema) CACHE[tId][CONTEXT$][k].schema = {}; | |
if (!CACHE[tId][CONTEXT$][k].schema.type && DtoSchema[_type]) { | |
CACHE[tId][CONTEXT$][k].schema = {...CACHE[tId][CONTEXT$][k].schema, ...DtoSchema[_type]}; | |
} | |
console.log(k, CACHE[tId][CONTEXT$][k].schema); | |
const isProtected = CACHE[tId][CONTEXT$][k].protected; | |
CACHE[tId][CONTEXT$][k] = { | |
"@id": CACHE[tId][CONTEXT$][k].id || k, | |
"@type": _type, | |
"@container": (CACHE[tId][CONTEXT$][k].container.length | |
? CACHE[tId][CONTEXT$][k].container | |
: []) | |
} | |
if (isProtected) CACHE[tId][CONTEXT$][k]["@protected"] = true; | |
if (targets.length === 2 && CACHE[targets[1]][CONTEXT$][k]) { | |
if (CACHE[targets[1]][CONTEXT$][k] && !equalsPrimitives(CACHE[tId][CONTEXT$][k], CACHE[targets[1]][CONTEXT$][k])) { | |
const wasProtected = CACHE[targets[1]][CONTEXT$][k]["@protected"]; | |
if (wasProtected) CACHE[tId][CONTEXT$][k] = CACHE[targets[1]][CONTEXT$][k]; | |
log[wasProtected ? "critical" : "warning"](`${tId}: JSON-LD context: Key has different definition in base class`); | |
log.warning(`The key ${k} was already defined as ${CACHE[targets[1]][CONTEXT$][k]["@id"]} in ${targets[1]}. | |
${wasProtected ? `It was protected, can't overwrite it.`: `Overwriting it as ${CACHE[targets[0]][CONTEXT$][k]}`}`) | |
} | |
} | |
checkPrefixOrUrl(CACHE[tId][CONTEXT$][k]["@id"], `${tId}:@id`, ctxPrefixes); | |
checkPrefixOrUrl(CACHE[tId][CONTEXT$][k]["@type"], `${tId}:@type`, ctxPrefixes); | |
if (CACHE[tId][CONTEXT$][k]["@container"].length) { | |
CACHE[tId][CONTEXT$][k]["@container"].forEach((container) => { | |
checkPrefixOrUrl(container, `${tId}:@container`, ctxPrefixes); | |
}) | |
} | |
} | |
const extended = targets.length > 1 ? CACHE[targets[1]][CONTEXT$] : {}; | |
CACHE[tId][CONTEXT$] = { | |
"@version": 1.1, | |
"@id": "", | |
...ctxPrefixes, | |
...extended, | |
...CACHE[tId][CONTEXT$] | |
}; | |
// Check if we have URLs for all prefixes | |
for (const k in CACHE[tId][CONTEXT$]) { | |
if (k.charAt(0) === "@") continue; | |
const prefix = k.split(":")[0]; | |
if (typeof CACHE[tId][CONTEXT$][k] === "string" && !!CACHE[tId][CONTEXT$][prefix]) continue; | |
if (typeof CACHE[tId][CONTEXT$][k] === "object" && !!CACHE[tId][CONTEXT$][prefix]) continue; | |
log.critical(`${tId}: JSON-LD context: Prefix not found`); | |
log.warning(`The prefix "${prefix}" could not be found. It will be ignored. | |
Keys beginning with "${prefix}:" in ${tId} like ${k} will be treated as plain JSON. | |
You can supply custom prefixes in the context-decorator as second property like | |
@context( "name", {[prefix]: IRI} )`); | |
} | |
CACHE[tId][CONTEXT$]["@id"] = tId.replace('redaktor.', `${contextPrefix}:`); | |
delete CACHE[tId][PREFIX$]; | |
const newClass = (class extends constructor { | |
constructor(...args: any[]) { | |
super(args[0]); | |
for (const k in args[0]) { this[k] = args[0][k]; } | |
} | |
toJSON() { | |
return { | |
"@context": [ | |
defaultContext, | |
CACHE[tId][CONTEXT$] | |
], | |
...this | |
} | |
} | |
async toHash() { | |
// if (this["toHash"]) return this["toHash"](); | |
const encoder = new TextEncoder(); | |
const json = JSON.stringify(this); | |
const data = encoder.encode(JSON.stringify(normal(json, {isJSON: true}))); | |
const buf = await crypto.subtle.digest("BLAKE3", data); | |
const hashArray = Array.from(new Uint8Array(buf)); | |
const hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")) | |
.join(""); // convert bytes to hex string | |
return hashHex; | |
} | |
} as T) | |
Object.freeze(newClass.prototype); | |
return newClass | |
} | |
} | |
/* | |
const schemaFns = { | |
"any": new Set(["type", "enum", "const", "maxItems", "minItems", "uniqueItems", "maxContains", "minContains"]), | |
"number": new Set(["multipleOf", "maximum", "exclusiveMaximum", "minimum", "exclusiveMinimum"]), | |
"string": new Set(["maxLength", "minLength", "pattern"]), | |
"array": | |
} | |
// "null", "boolean", "object", "array", "integer", "number", or "string" | |
const typeProxy = (ret: any, schemaType: string) => ({ | |
get: (object, property) => { | |
return (v: any) => { | |
console.log(property, v) | |
if (v) { | |
return new Proxy(object, typeProxy(ret, schemaType)); | |
} | |
return ret; | |
} | |
} | |
}); | |
type.decimal = new Proxy(type(D.decimal), typeProxy(type(D.decimal), "number")); | |
*/ | |
type SchemaStringFormat = "date-time"|"date"|"time"|"duration"|"email"|"idn-email"|"hostname"|"idn-hostname"| | |
"uri"|"uri-reference"|"iri"|"iri-reference"|"uuid"|"uri-template"|"json-pointer"|"relative-json-pointer"|"regex"| | |
// custom: | |
"json"|"booleanString"|"numberString"|"uppercase"|"lowercase"|"alpha"|"alphaNumeric"|"phoneNumber"|"phoneMobile"| | |
"locale"|"country"|"calendar"|"collation"|"currency"|"numberingSystem"|"timeZone"|"unit"; | |
/* | |
https://github.com/typestack/class-validator | |
Contains | |
NotContains | |
NotEquals | |
IsNotEmpty | |
MinDate | |
MaxDate | |
*/ | |
const everyRuntime = (schemaType: string, dType: string, ret: any) => ({ | |
enum: (v: any[]) => { | |
v = toArray(v); | |
curSchema = {type: schemaType, ...curSchema, enum: Array.from(new Set(v))}; | |
return Object.assign(type(D[dType], [], curSchema), ret); | |
}, | |
const: (v: any) => { | |
curSchema = {type: schemaType, ...curSchema, const: v}; | |
return Object.assign(type(D[dType], [], curSchema), ret); | |
} | |
}); | |
const Dnr = {decimal: "number", int: "integer"}; | |
const nrRuntime = (nrType: "decimal"|"int" = "decimal", fixedSchema = {}) => ({ | |
maximum: (v: number) => { | |
curSchema = {type: Dnr[nrType], ...curSchema, ...fixedSchema, maximum: v}; | |
return Object.assign(type(D[nrType], [], curSchema), nrRuntime(nrType, fixedSchema)); | |
}, | |
exclusiveMaximum: (v: number) => { | |
curSchema = {type: Dnr[nrType], ...curSchema, ...fixedSchema, exclusiveMaximum: v}; | |
return Object.assign(type(D[nrType], [], curSchema), nrRuntime(nrType, fixedSchema)); | |
}, | |
minimum: (v: number) => { | |
curSchema = {type: Dnr[nrType], ...curSchema, ...fixedSchema, minimum: v}; | |
return Object.assign(type(D[nrType], [], curSchema), nrRuntime(nrType, fixedSchema)); | |
}, | |
exclusiveMinimum: (v: number) => { | |
curSchema = {type: Dnr[nrType], ...curSchema, ...fixedSchema, exclusiveMinimum: v}; | |
return Object.assign(type(D[nrType], [], curSchema), nrRuntime(nrType, fixedSchema)); | |
}, | |
multipleOf: (v: number) => { | |
curSchema = {type: Dnr[nrType], ...curSchema, ...fixedSchema, multipleOf: v}; | |
return Object.assign(type(D[nrType], [], curSchema), nrRuntime(nrType, fixedSchema)); | |
} | |
}); | |
const numberRuntime = (nrType: "decimal"|"int" = "decimal", fixedSchema = {}) => ({ | |
...everyRuntime(Dnr[nrType], nrType, nrRuntime(nrType, fixedSchema)), | |
...nrRuntime(nrType, fixedSchema) | |
}); | |
const strRuntime = (strType: "string"|"token"|"uri"|"id"|"json" = "string", fixedSchema = {}) => ({ | |
format: (v: SchemaStringFormat) => { | |
if (!curSchema.format) curSchema.format = []; | |
curSchema = {type: "string", ...curSchema, format: curSchema.format.concat(toArray(v))}; | |
return Object.assign(type(D[strType], [], curSchema), strRuntime(strType, fixedSchema)); | |
}, | |
maxLength: (v: number) => { | |
curSchema = {type: "string", ...curSchema, ...fixedSchema, maxLength: v}; | |
return Object.assign(type(D[strType], [], curSchema), strRuntime(strType, fixedSchema)); | |
}, | |
minLength: (v: number) => { | |
curSchema = {type: "string", ...curSchema, ...fixedSchema, minLength: v}; | |
return Object.assign(type(D[strType], [], curSchema), strRuntime(strType, fixedSchema)); | |
}, | |
pattern: (v: string) => { | |
curSchema = {type: "string", ...curSchema, ...fixedSchema, pattern: v}; | |
return Object.assign(type(D[strType], [], curSchema), strRuntime(strType, fixedSchema)); | |
} | |
}); | |
const stringRuntime = (strType: "string"|"token"|"uri"|"id"|"json" = "string", fixedSchema = {}) => ({ | |
...everyRuntime("string", strType, strRuntime(strType, fixedSchema)), | |
...strRuntime(strType, fixedSchema) | |
}); | |
type.boolean = type(D.boolean); | |
type.decimal = Object.assign(type(D.decimal), numberRuntime()); | |
type.integer = Object.assign(type(D.int), numberRuntime("int")); | |
type.integerPositive = Object.assign(type(D.int), numberRuntime("int"), { exclusiveMinimum: 0 }); | |
type.string = Object.assign(type(D.string), stringRuntime()); | |
type.token = Object.assign(type(D.token), stringRuntime("token")); | |
type.uri = Object.assign(type(D.uri), stringRuntime("uri"), { format: "uri" }); | |
type.id = Object.assign(type(D.id), stringRuntime("id"), { format: "iri" }); | |
type.idOrObject = Object.assign(type(D.id, ["@set"]), stringRuntime("id"), { format: "iri" }); | |
type.idOnly = Object.assign(type(D.id, ["@set", "@id"]), stringRuntime("id"), { format: "iri" }); | |
type.json = Object.assign(type(D.json), stringRuntime("json"), { format: "redaktor-json" }); | |
// TODO set, list, array, allRuntime : | |
type.set = type(D.set); | |
// TODO object | |
/* | |
export const functional = { | |
id: type([FUNCTIONAL, "owl:ObjectProperty", "@id"]), | |
string: type([FUNCTIONAL, DATATYPE, "xsd:string"]), | |
uri: type([FUNCTIONAL, DATATYPE, "xsd:anyURI"]), | |
token: type([FUNCTIONAL, DATATYPE, "xsd:token"]), | |
decimal: type([FUNCTIONAL, DATATYPE, "xsd:decimal"]), | |
int: type([FUNCTIONAL, DATATYPE, "xsd:int"]), | |
integerPositive: type([FUNCTIONAL, DATATYPE, "xsd:nonNegativeInteger"]), | |
}; | |
*/ |
This file contains 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 { Reflect } from "https://deno.land/x/reflect_metadata@v0.1.12/mod.ts"; | |
import { context, id, type, container, protect } from "@jsonld"; | |
@context("as") | |
class AS { | |
constructor(args: AS) {} | |
@id("as:name") @container.set @type.string @protect | |
protected name: string | string[]; | |
xy: any | |
} | |
@context("redaktor") | |
class MyClass extends AS { | |
constructor(args: MyClass) { super(args) } | |
@id("wdt:P2048") @type.integerPositive | |
population: number; | |
@id("redaktor:test") @type.idOrObject @protect | |
protected anotherProperty: string; | |
// SHOULD error cause protected: | |
/* | |
@id("as:name") @container.set @type.string | |
name: string | string[]; | |
*/ | |
} | |
const x = new MyClass({population: 2, name: "Ed", xy:() => { return ""}}); | |
const JSONRES = JSON.stringify(x, null, 2); // <- THE MAGIC | |
console.log(x, '___', JSONRES, '___'); | |
// Retrieve the metadata for the decorator | |
const metadata = Reflect.getMetadata("id-decorator", MyClass.prototype, "population"); | |
console.log(3, metadata); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment