JSDoc complete type check

This commit is contained in:
barsdeveloper
2022-10-09 11:43:28 +02:00
parent 91e1e0885e
commit cdc5e5b91b
68 changed files with 1603 additions and 648 deletions

View File

@@ -1,15 +1,25 @@
import GeneralSerializer from "./GeneralSerializer"
/** @typedef {import("../entity/IEntity").default} IEntity */
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/** @template {IEntity | Boolean | Number | String} T */
/**
* @template {AnyValue} T
* @extends {GeneralSerializer<T>}
*/
export default class CustomSerializer extends GeneralSerializer {
#objectWriter
/**
* @param {(v: T, insideString: Boolean) => String} objectWriter
* @param {new () => T} entityType
* @param {AnyValueConstructor<T>} entityType
*/
constructor(objectWriter, entityType) {
super(undefined, entityType)

View File

@@ -1,12 +1,22 @@
import Grammar from "./Grammar"
import ISerializer from "./ISerializer"
/** @typedef {import("../entity/IEntity").default} IEntity */
/**
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/** @template {IEntity} T */
/**
* @template {AnyValue} T
* @extends ISerializer<T>
*/
export default class GeneralSerializer extends ISerializer {
/** @param {new () => T} entityType */
/** @param {AnyValueConstructor<T>} entityType */
constructor(wrap, entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
wrap = wrap ?? (v => `(${v})`)
super(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter)
@@ -18,6 +28,7 @@ export default class GeneralSerializer extends ISerializer {
* @returns {T}
*/
read(value) {
// @ts-expect-error
let grammar = Grammar.getGrammarForType(ISerializer.grammar, this.entityType)
const parseResult = grammar.parse(value)
if (!parseResult.status) {

View File

@@ -1,3 +1,4 @@
// @ts-nocheck
import FunctionReferenceEntity from "../entity/FunctionReferenceEntity"
import GuidEntity from "../entity/GuidEntity"
import IdentifierEntity from "../entity/IdentifierEntity"
@@ -20,6 +21,14 @@ import Utility from "../Utility"
import VectorEntity from "../entity/VectorEntity"
/** @typedef {import("../entity/IEntity").default} IEntity */
/**
* @template {IEntity} T
* @typedef {import("../entity/IEntity").IEntityConstructor<T>} IEntityConstructor
*/
/**
* @template T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
let P = Parsimmon
@@ -27,7 +36,14 @@ export default class Grammar {
/* --- Factory --- */
static getGrammarForType(r, attributeType, defaultGrammar) {
/**
* @template T, U
* @param {Grammar} r
* @param {AnyValueConstructor<T>} attributeType
* @param {Parsimmon<U>} defaultGrammar
* @returns
*/
static getGrammarForType(r, attributeType, defaultGrammar = r.AttributeAnyValue) {
if (attributeType instanceof TypeInitialization) {
let result = Grammar.getGrammarForType(r, attributeType.type, defaultGrammar)
if (attributeType.serialized && !(attributeType.type instanceof String)) {
@@ -91,6 +107,12 @@ export default class Grammar {
}
}
/**
* @param {Grammar} r
* @param {IEntityConstructor<IEntity>} entityType
* @param {Parsimmon.Parser<String>} valueSeparator
* @returns
*/
static createPropertyGrammar = (r, entityType, valueSeparator = P.string("=").trim(P.optWhitespace)) =>
r.AttributeName.skip(valueSeparator)
.chain(attributeName => {
@@ -104,6 +126,11 @@ export default class Grammar {
)
})
/**
* @param {Grammar} r
* @param {IEntityConstructor<IEntity>} entityType
* @returns
*/
static createEntityGrammar = (r, entityType) =>
P.seqMap(
entityType.lookbehind
@@ -123,14 +150,19 @@ export default class Grammar {
/* --- General --- */
/** @param {Grammar} r */
InlineWhitespace = r => P.regex(/[^\S\n]+/).desc("inline whitespace")
/** @param {Grammar} r */
InlineOptWhitespace = r => P.regex(/[^\S\n]*/).desc("inline optional whitespace")
/** @param {Grammar} r */
MultilineWhitespace = r => P.regex(/[^\S\n]*\n\s*/).desc("whitespace with at least a newline")
/** @param {Grammar} r */
Null = r => P.seq(P.string("("), r.InlineOptWhitespace, P.string(")")).map(_ => null).desc("null: ()")
/** @param {Grammar} r */
Boolean = r => P.alt(
P.string("True"),
P.string("true"),
@@ -139,19 +171,26 @@ export default class Grammar {
).map(v => v.toLocaleLowerCase() === "true" ? true : false)
.desc("either True or False")
/** @param {Grammar} r */
HexDigit = r => P.regex(/[0-9a-fA-f]/).desc("hexadecimal digit")
/** @param {Grammar} r */
Number = r => P.regex(/[\-\+]?[0-9]+(?:\.[0-9]+)?/).map(Number).desc("a number")
/** @param {Grammar} r */
NaturalNumber = r => P.regex(/0|[1-9]\d*/).map(Number).desc("a natural number")
/** @param {Grammar} r */
ColorNumber = r => r.NaturalNumber.assert(n => 0 <= n && n < 256, "the color must be between 0 and 256 excluded")
/** @param {Grammar} r */
Word = r => P.regex(/[a-zA-Z]+/).desc("a word")
/** @param {Grammar} r */
String = r => P.regex(/(?:[^"\\]|\\.)*/).wrap(P.string('"'), P.string('"')).map(Utility.unescapeString)
.desc('string (with possibility to escape the quote using \")')
/** @param {Grammar} r */
ReferencePath = r => P.seq(
P.string("/"),
r.PathSymbol
@@ -164,20 +203,27 @@ export default class Grammar {
.tie()
.desc('a path (words with possibly underscore, separated by ".", separated by "/")')
/** @param {Grammar} r */
AttributeName = r => r.Word.sepBy1(P.string(".")).tieWith(".").desc('words separated by ""')
/* --- Entity --- */
/** @param {Grammar} r */
None = r => P.string("None").map(_ => new ObjectReferenceEntity({ type: "None", path: "" })).desc("none")
/** @param {Grammar} r */
Integer = r => P.regex(/[\-\+]?[0-9]+/).map(v => new IntegerEntity(v)).desc("an integer")
/** @param {Grammar} r */
Guid = r => r.HexDigit.times(32).tie().map(v => new GuidEntity({ value: v })).desc("32 digit hexadecimal value")
/** @param {Grammar} r */
Identifier = r => P.regex(/\w+/).map(v => new IdentifierEntity(v))
/** @param {Grammar} r */
PathSymbol = r => P.regex(/[0-9\w]+/).map(v => new PathSymbolEntity({ value: v }))
/** @param {Grammar} r */
Reference = r => P.alt(
r.None,
...[r.ReferencePath.map(path => new ObjectReferenceEntity({ type: "", path: path }))]
@@ -197,6 +243,7 @@ export default class Grammar {
r.Word.map(type => new ObjectReferenceEntity({ type: type, path: "" })),
)
/** @param {Grammar} r */
LocalizedText = r => P.seqMap(
P.string(LocalizedTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")), // Goes into _0 (ignored)
r.String.trim(P.optWhitespace), // Goes into namespace
@@ -212,12 +259,14 @@ export default class Grammar {
})
)
/** @param {Grammar} r */
InvariantText = r => r.String.trim(P.optWhitespace).wrap(
P.string(InvariantTextEntity.lookbehind).skip(P.optWhitespace).skip(P.string("(")),
P.string(")")
)
.map(value => new InvariantTextEntity({ value: value }))
/** @param {Grammar} r */
AttributeAnyValue = r => P.alt(
r.Null,
r.None,
@@ -233,6 +282,7 @@ export default class Grammar {
r.LinearColor,
)
/** @param {Grammar} r */
PinReference = r => P.seqMap(
r.PathSymbol, // Goes into objectNAme
P.whitespace, // Goes into _ (ignored)
@@ -243,10 +293,13 @@ export default class Grammar {
})
)
/** @param {Grammar} r */
Vector = r => Grammar.createEntityGrammar(r, VectorEntity)
/** @param {Grammar} r */
Rotator = r => Grammar.createEntityGrammar(r, RotatorEntity)
/** @param {Grammar} r */
SimpleSerializationRotator = r => P.seqMap(
r.Number,
P.string(",").trim(P.optWhitespace),
@@ -260,6 +313,7 @@ export default class Grammar {
})
)
/** @param {Grammar} r */
SimpleSerializationVector = r => P.seqMap(
r.Number,
P.string(",").trim(P.optWhitespace),
@@ -273,10 +327,13 @@ export default class Grammar {
})
)
/** @param {Grammar} r */
LinearColor = r => Grammar.createEntityGrammar(r, LinearColorEntity)
/** @param {Grammar} r */
FunctionReference = r => Grammar.createEntityGrammar(r, FunctionReferenceEntity)
/** @param {Grammar} r */
KeyBinding = r => P.alt(
r.Identifier.map(identifier => new KeyBindingEntity({
Key: identifier
@@ -284,8 +341,10 @@ export default class Grammar {
Grammar.createEntityGrammar(r, KeyBindingEntity)
)
/** @param {Grammar} r */
Pin = r => Grammar.createEntityGrammar(r, PinEntity)
/** @param {Grammar} r */
CustomProperties = r =>
P.string("CustomProperties")
.then(P.whitespace)
@@ -297,7 +356,7 @@ export default class Grammar {
Utility.objectSet(entity, ["CustomProperties"], properties, true)
})
/** @returns {Parsimmon.Parser<ObjectEntity>} */
/** @param {Grammar} r */
Object = r => P.seqMap(
P.seq(P.string("Begin"), P.whitespace, P.string("Object"), P.whitespace),
P
@@ -319,6 +378,7 @@ export default class Grammar {
/* --- Others --- */
/** @param {Grammar} r */
LinearColorFromHex = r => P
.string("#")
.then(r.HexDigit.times(2).tie().times(3, 4))
@@ -330,6 +390,7 @@ export default class Grammar {
A: A ? parseInt(A, 16) / 255 : 1,
}))
/** @param {Grammar} r */
LinearColorFromRGBList = r => P.seqMap(
r.ColorNumber,
P.string(",").skip(P.optWhitespace),
@@ -344,6 +405,7 @@ export default class Grammar {
})
)
/** @param {Grammar} r */
LinearColorFromRGB = r => P.string("rgb").then(
r.LinearColorFromRGBList.wrap(
P.regex(/\(\s*/),
@@ -351,6 +413,7 @@ export default class Grammar {
)
)
/** @param {Grammar} r */
LinearColorFromRGBA = r => P.string("rgba").then(
P.seqMap(
r.ColorNumber,
@@ -372,6 +435,7 @@ export default class Grammar {
)
)
/** @param {Grammar} r */
LinearColorFromAnyColor = r => P.alt(
r.LinearColorFromRGBList,
r.LinearColorFromHex,

View File

@@ -1,22 +1,38 @@
import Grammar from "./Grammar"
import IEntity from "../entity/IEntity"
import Parsimmon from "parsimmon"
import SerializerFactory from "./SerializerFactory"
import TypeInitialization from "../entity/TypeInitialization"
import Utility from "../Utility"
/** @template {IEntity} T */
/**
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/** @template {AnyValue} T */
export default class ISerializer {
// @ts-expect-error
static grammar = Parsimmon.createLanguage(new Grammar())
constructor(entityType, prefix, separator, trailingSeparator, attributeValueConjunctionSign, attributeKeyPrinter) {
/** @param {AnyValueConstructor<T>} entityType */
constructor(
entityType,
prefix = "",
separator = ",",
trailingSeparator = false,
attributeValueConjunctionSign = "=",
attributeKeyPrinter = k => k.join(".")
) {
this.entityType = entityType
this.prefix = prefix ?? ""
this.separator = separator ?? ","
this.trailingSeparator = trailingSeparator ?? false
this.attributeValueConjunctionSign = attributeValueConjunctionSign ?? "="
this.attributeKeyPrinter = attributeKeyPrinter ?? (k => k.join("."))
this.prefix = prefix
this.separator = separator
this.trailingSeparator = trailingSeparator
this.attributeValueConjunctionSign = attributeValueConjunctionSign
this.attributeKeyPrinter = attributeKeyPrinter
}
/**
@@ -27,12 +43,8 @@ export default class ISerializer {
return this.read(value)
}
/**
* @param {T} object
* @param {Boolean} insideString
* @returns {String}
*/
serialize(object, insideString, entity = object) {
/** @param {T} object */
serialize(object, insideString = false, entity = object) {
return this.write(entity, object, insideString)
}
@@ -54,6 +66,7 @@ export default class ISerializer {
}
/**
* @param {AnyValue} value
* @param {String[]} fullKey
* @param {Boolean} insideString
*/
@@ -103,6 +116,7 @@ export default class ISerializer {
}
showProperty(entity, object, attributeKey, attributeValue) {
// @ts-expect-error
const attributes = this.entityType.attributes
const attribute = Utility.objectGet(attributes, attributeKey)
if (attribute instanceof TypeInitialization) {

View File

@@ -1,14 +1,19 @@
import Utility from "../Utility"
/** @typedef {import("../entity/IEntity").default} IEntity */
/**
* @template {IEntity} T
* @typedef {import("../entity/IEntity").default} IEntity
* @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue
*/
/**
* @template T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
* @typedef {import("./ISerializer").default<T>} ISerializer
*/
export default class SerializerFactory {
/** @type {Map<T, ISerializer<T>>} */
/** @type {Map<AnyValueConstructor<AnyValue>, ISerializer<AnyValue>>} */
static #serializers = new Map()
static registerSerializer(entity, object) {
@@ -16,8 +21,8 @@ export default class SerializerFactory {
}
/**
* @template {IEntity} T
* @param {T} entity
* @template {AnyValue} T
* @param {AnyValueConstructor<T>} entity
*/
static getSerializer(entity) {
return SerializerFactory.#serializers.get(entity)

View File

@@ -1,12 +1,18 @@
import Utility from "../Utility"
import GeneralSerializer from "./GeneralSerializer"
/** @typedef {import("../entity/IEntity").default} IEntity */
/** @template {IEntity} T */
/** @typedef {import("../entity/TypeInitialization").AnyValue} AnyValue */
/**
* @template {AnyValue} T
* @typedef {import("../entity/TypeInitialization").AnyValueConstructor<T>} AnyValueConstructor
*/
/**
* @template {AnyValue} T
* @extends {GeneralSerializer<T>}
*/
export default class ToStringSerializer extends GeneralSerializer {
/** @param {new () => T} entityType */
/** @param {AnyValueConstructor<T>} entityType */
constructor(entityType) {
super(undefined, entityType)
}

View File

@@ -14,13 +14,13 @@ import ObjectSerializer from "./ObjectSerializer"
import PathSymbolEntity from "../entity/PathSymbolEntity"
import PinEntity from "../entity/PinEntity"
import PinReferenceEntity from "../entity/PinReferenceEntity"
import RotatorEntity from "../entity/RotatorEntity"
import SerializerFactory from "./SerializerFactory"
import SimpleSerializationRotatorEntity from "../entity/SimpleSerializationRotatorEntity"
import SimpleSerializationVectorEntity from "../entity/SimpleSerializationVectorEntity"
import ToStringSerializer from "./ToStringSerializer"
import Utility from "../Utility"
import VectorEntity from "../entity/VectorEntity"
import RotatorEntity from "../entity/RotatorEntity"
import SimpleSerializationRotatorEntity from "../entity/SimpleSerializationRotatorEntity"
export default function initializeSerializerFactory() {
@@ -143,7 +143,9 @@ export default function initializeSerializerFactory() {
String,
new CustomSerializer(
(value, insideString) => insideString
// @ts-expect-error
? Utility.escapeString(value)
// @ts-expect-error
: `"${Utility.escapeString(value)}"`,
String
)