From a56ba6296473e08c522d20067afe6c9ae310b373 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sun, 10 Dec 2023 22:49:20 -0300 Subject: [PATCH 1/9] Get all properties modifiers --- .../tsruntime/src/transform/makeLiteral.ts | 18 +++++-- packages/tsruntime/src/transform/reflect.ts | 53 +++++++++++++++++-- packages/tsruntime/src/transform/types.ts | 4 +- packages/tsruntime/tsconfig.json | 5 +- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/packages/tsruntime/src/transform/makeLiteral.ts b/packages/tsruntime/src/transform/makeLiteral.ts index c3e1699..e6193fc 100644 --- a/packages/tsruntime/src/transform/makeLiteral.ts +++ b/packages/tsruntime/src/transform/makeLiteral.ts @@ -15,7 +15,7 @@ function getExpressionForPropertyName(name: ts.PropertyName) { //copied from typ } -export function makeLiteral(type: ReflectedType, modifier?: ts.ModifierFlags): ts.ObjectLiteralExpression { +export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags[]): ts.ObjectLiteralExpression { const assigns = [] const kindAssign = ts.factory.createPropertyAssignment("kind", ts.factory.createNumericLiteral(type.kind)) const kindAssignComment = ts.addSyntheticTrailingComment(kindAssign, ts.SyntaxKind.MultiLineCommentTrivia, TypeKind[type.kind], false) @@ -25,8 +25,13 @@ export function makeLiteral(type: ReflectedType, modifier?: ts.ModifierFlags): t assigns.push(ts.factory.createPropertyAssignment("initializer", type.initializer)) } - if (modifier !== undefined) { - assigns.push(ts.factory.createPropertyAssignment("modifiers", ts.factory.createNumericLiteral(modifier))); + if (Array.isArray(modifiers)) { + assigns.push(ts.factory.createPropertyAssignment( + "modifiers", + ts.factory.createArrayLiteralExpression( + modifiers.map(mod => ts.factory.createNumericLiteral(mod)) + ) + )); } switch (type.kind) { @@ -54,7 +59,12 @@ export function makeLiteral(type: ReflectedType, modifier?: ts.ModifierFlags): t ts.factory.createPropertyAssignment("parameters", ts.factory.createArrayLiteralExpression( parameters.map(({name, modifiers, type}) => ts.factory.createObjectLiteralExpression([ ts.factory.createPropertyAssignment("name", ts.factory.createStringLiteral(name)), - ts.factory.createPropertyAssignment("modifiers", ts.factory.createNumericLiteral(modifiers)), + ts.factory.createPropertyAssignment( + "modifiers", + ts.factory.createArrayLiteralExpression( + modifiers.map(mod => ts.factory.createNumericLiteral(mod)) + ), + ), ts.factory.createPropertyAssignment("type", makeLiteral(type)), ])) )) diff --git a/packages/tsruntime/src/transform/reflect.ts b/packages/tsruntime/src/transform/reflect.ts index e7e71ef..9dd14c2 100644 --- a/packages/tsruntime/src/transform/reflect.ts +++ b/packages/tsruntime/src/transform/reflect.ts @@ -55,6 +55,11 @@ namespace Normalizers { } export function getReflect(ctx: Ctx) { + const accessModifiers = [ + ts.ModifierFlags.Private, + ts.ModifierFlags.Protected, + ts.ModifierFlags.Public, + ]; function serializeUnion(type: ts.UnionType): ReflectedType { const nestedTypes = type.types.map(t => reflectType(t)); const normalizedTypes = Normalizers.normalizeUnion(nestedTypes); @@ -141,7 +146,15 @@ export function getReflect(ctx: Ctx) { const decl = sym.declarations![0]; const type = ctx.checker.getTypeOfSymbolAtLocation(sym, ctx.node); const serializedType = reflectType(type); - const modifierFlags = ts.getCombinedModifierFlags(decl); + const modifiers = getModifiersFromDeclaration(decl, [ + ts.ModifierFlags.Private, + ts.ModifierFlags.Protected, + ts.ModifierFlags.Public, + ts.ModifierFlags.Readonly, + ts.ModifierFlags.Override, + ts.ModifierFlags.Static, + ts.ModifierFlags.Abstract, + ]); const name = getPropertyName(sym); const initializer = ts.isPropertyDeclaration(sym.valueDeclaration!) @@ -150,7 +163,7 @@ export function getReflect(ctx: Ctx) { return { name: name, - modifiers: modifierFlags, + modifiers, type: {...serializedType, initializer}, }; } @@ -158,7 +171,13 @@ export function getReflect(ctx: Ctx) { function serializeConstructorParameter(param: ts.Symbol): ConstructorParameter { const decl = param.declarations![0]; const type = reflectType(ctx.checker.getTypeOfSymbolAtLocation(param, decl)); - const modifiers = ts.getCombinedModifierFlags(decl); + const modifiers = getModifiersFromDeclaration(decl, [ + ts.ModifierFlags.Private, + ts.ModifierFlags.Protected, + ts.ModifierFlags.Public, + ts.ModifierFlags.Readonly, + ts.ModifierFlags.Override, + ]); const initializer = param.valueDeclaration && ts.isParameter(param.valueDeclaration) ? serializeInitializer(param.valueDeclaration) @@ -228,6 +247,34 @@ export function getReflect(ctx: Ctx) { // return { kind: TypeKind.Unknown2 }; } + function getModifiersFromDeclaration(decl: ts.Declaration, includesModifiers: ts.ModifierFlags[] = []) { + const modifierFlags = ts.getCombinedModifierFlags(decl); + const modifiers = modifierFlags === 0 + ? [ts.ModifierFlags.None] + : getModifiersByBruteForce(modifierFlags).filter(mod => includesModifiers.length === 0 || includesModifiers.includes(mod)); + + if (!modifiers.some(mod => accessModifiers.includes(mod)) && !modifiers.includes(ts.ModifierFlags.None)) { + modifiers.push(ts.ModifierFlags.None); + } + return modifiers.sort((a, b) => Number(a) - Number(b)); + } + + function getModifiersByBruteForce(modifierFlags: ts.ModifierFlags) { + const modifiers = []; + const modifiersToCheck = Object + .keys(ts.ModifierFlags) + .filter(k => isNaN(Number(k))) + .map(k => ts.ModifierFlags[k as keyof typeof ts.ModifierFlags]); + + for (const mod of modifiersToCheck) { + if (modifierFlags & mod) { + modifiers.push(mod); + } + } + + return modifiers; + } + function reflectType(type: ts.Type): ReflectedType { if (type.flags & ts.TypeFlags.Any) { return { kind: TypeKind.Any }; diff --git a/packages/tsruntime/src/transform/types.ts b/packages/tsruntime/src/transform/types.ts index a8c2850..454e828 100644 --- a/packages/tsruntime/src/transform/types.ts +++ b/packages/tsruntime/src/transform/types.ts @@ -59,7 +59,7 @@ type Override2 = Override // type Override2 = T extends {[key: string]: infer R} ? {[key: string]: R extends Types.ReflectedType ? ReflectedType : R}: T -type Properties = Array<{ name: ts.PropertyName; type: ReflectedType; modifiers: Types.ModifierFlags }>; +type Properties = Array<{ name: ts.PropertyName; type: ReflectedType; modifiers: Types.ModifierFlags[] }>; export type ObjectType = Override< Types.ObjectType, { @@ -90,7 +90,7 @@ export type ReferenceType = Override< export interface ConstructorParameter { name: string; - modifiers: ts.ModifierFlags; + modifiers: ts.ModifierFlags[]; type: ReflectedType; } diff --git a/packages/tsruntime/tsconfig.json b/packages/tsruntime/tsconfig.json index 1927216..d56b1fa 100644 --- a/packages/tsruntime/tsconfig.json +++ b/packages/tsruntime/tsconfig.json @@ -2,9 +2,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "outDir": "dist", + "lib": ["dom", "es2016"], + "outDir": "dist" }, "include": [ "src/**/*" ] -} \ No newline at end of file +} From c720e4b7f257bacf853615e089fe288eb30aec38 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sun, 10 Dec 2023 22:49:53 -0300 Subject: [PATCH 2/9] Add build:watch test script --- packages/tests/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/tests/package.json b/packages/tests/package.json index 3fdc93e..4c2a5a2 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -4,7 +4,8 @@ "private": true, "scripts": { "test": "npm run build && jest --no-cache", - "build": "rimraf ./dist && tspc" + "build": "rimraf ./dist && tspc", + "build:watch": "rimraf ./dist && tspc -w" }, "repository": { "type": "git", From 14ccadf3927155dcf1fbc4dc519dca6f97d959c4 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sun, 10 Dec 2023 22:50:12 -0300 Subject: [PATCH 3/9] Update modifier tests --- .../tests/src/types/classConstructor.test.ts | 8 ++++---- packages/tests/src/types/interfaces.test.ts | 4 ++-- packages/tests/src/types/objectTypes.test.ts | 2 +- .../src/types/propertyInitializer.test.ts | 18 +++++++++--------- packages/tests/src/types/transform.test.ts | 4 ++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/tests/src/types/classConstructor.test.ts b/packages/tests/src/types/classConstructor.test.ts index b3c1ad1..07a4417 100644 --- a/packages/tests/src/types/classConstructor.test.ts +++ b/packages/tests/src/types/classConstructor.test.ts @@ -17,12 +17,12 @@ describe("Class Constructor", () => { parameters: [ { name: "foo", - modifiers: 0, + modifiers: [Types.ModifierFlags.None], type: {kind: Types.TypeKind.String}, }, { name: "bar", - modifiers: 0, + modifiers: [Types.ModifierFlags.None], type: {kind: Types.TypeKind.Number}, }, ], @@ -44,11 +44,11 @@ describe("Class Constructor", () => { parameters: [ { name: "foo", - modifiers: Types.ModifierFlags.Public, + modifiers: [Types.ModifierFlags.Public], }, { name: "bar", - modifiers: Types.ModifierFlags.Private, + modifiers: [Types.ModifierFlags.Private], }, ], }, diff --git a/packages/tests/src/types/interfaces.test.ts b/packages/tests/src/types/interfaces.test.ts index 58b7296..20728f6 100644 --- a/packages/tests/src/types/interfaces.test.ts +++ b/packages/tests/src/types/interfaces.test.ts @@ -25,7 +25,7 @@ interface IExtends extends IExtended { } -const stringType = {kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None} +const stringType = {kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None]} describe("interfaces", () => { @@ -42,7 +42,7 @@ describe("interfaces", () => { [constKey]: stringType, ['computed-string']: stringType, [uniqSymb]: stringType, - method: {kind: Types.TypeKind.Function, modifiers: Types.ModifierFlags.None} + method: {kind: Types.TypeKind.Function, modifiers: [Types.ModifierFlags.None]} } }); }); diff --git a/packages/tests/src/types/objectTypes.test.ts b/packages/tests/src/types/objectTypes.test.ts index 257cf6b..e02b93c 100644 --- a/packages/tests/src/types/objectTypes.test.ts +++ b/packages/tests/src/types/objectTypes.test.ts @@ -6,7 +6,7 @@ const constKey = "some-key"; const uniqSymb = Symbol("some symb"); -const stringType = {kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None} +const stringType = {kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None]} type ObjectType = { key: string diff --git a/packages/tests/src/types/propertyInitializer.test.ts b/packages/tests/src/types/propertyInitializer.test.ts index 22db578..009b85d 100644 --- a/packages/tests/src/types/propertyInitializer.test.ts +++ b/packages/tests/src/types/propertyInitializer.test.ts @@ -40,17 +40,17 @@ function typeIsEqual(type: Types.ReflectedType, val: any) { describe("class properties initializers", () => { it("primitive types", () => { - typeIsEqual(getPropType("string"), { kind: TypeKind.String, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("string"), { kind: TypeKind.String, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("string"), 'string'); - typeIsEqual(getPropType("number"), { kind: TypeKind.Number, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("number"), { kind: TypeKind.Number, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("number"), 42); - typeIsEqual(getPropType("true"), { kind: TypeKind.Boolean, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("true"), { kind: TypeKind.Boolean, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("true"), true); - typeIsEqual(getPropType("false"), { kind: TypeKind.Boolean, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("false"), { kind: TypeKind.Boolean, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("false"), false); - typeIsEqual(getPropType("null"), { kind: TypeKind.Null, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("null"), { kind: TypeKind.Null, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("null"), null); - typeIsEqual(getPropType("undefined"), { kind: TypeKind.Undefined, modifiers: Types.ModifierFlags.None }); + typeIsEqual(getPropType("undefined"), { kind: TypeKind.Undefined, modifiers: [Types.ModifierFlags.None] }); initializerIsEqual(getPropType("undefined"), undefined); }); it("arrays", () => { @@ -60,7 +60,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: Array, - modifiers: Types.ModifierFlags.None, + modifiers: [Types.ModifierFlags.None], arguments: [{ kind: TypeKind.String }] }); initializerIsEqual(type, ["string"]); @@ -72,7 +72,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: Cls, - modifiers: Types.ModifierFlags.None, + modifiers: [Types.ModifierFlags.None], arguments: [] }); expect(type.initializer).not.toBeUndefined() @@ -84,7 +84,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: GenericCls, - modifiers: Types.ModifierFlags.None, + modifiers: [Types.ModifierFlags.None], arguments: [{ kind: Types.TypeKind.String }] }); expect(type.initializer).not.toBeUndefined() diff --git a/packages/tests/src/types/transform.test.ts b/packages/tests/src/types/transform.test.ts index bd467db..2e0ef42 100644 --- a/packages/tests/src/types/transform.test.ts +++ b/packages/tests/src/types/transform.test.ts @@ -39,7 +39,7 @@ describe("transform", () => { exported: { kind: Types.TypeKind.Reference, type: ExportedClass, - modifiers: Types.ModifierFlags.None, + modifiers: [Types.ModifierFlags.None], arguments: [] } }, @@ -71,7 +71,7 @@ describe("transform", () => { name: "TestClass", kind: Types.TypeKind.Class, properties: { - prop: { kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None } + prop: { kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None] } }, constructors: [{modifiers: 0, parameters: []}], }); From ea8d550deb55f07a5fa5edbd396d419df22c8dbb Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sun, 10 Dec 2023 22:50:32 -0300 Subject: [PATCH 4/9] Add test to check all modifiers --- .../tests/src/types/propertyModifiers.test.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 packages/tests/src/types/propertyModifiers.test.ts diff --git a/packages/tests/src/types/propertyModifiers.test.ts b/packages/tests/src/types/propertyModifiers.test.ts new file mode 100644 index 0000000..830c551 --- /dev/null +++ b/packages/tests/src/types/propertyModifiers.test.ts @@ -0,0 +1,56 @@ +import {getClassType, Reflective, Types} from "tsruntime"; + +class Cls { + f!: string; + protected g!: string; + constructor() { + } +} + +@Reflective +abstract class SubCls extends Cls { + a!: string; + public b!: string; + protected c!: string; + private d!: string; + readonly e!: string; + override f!: string; + protected override readonly g!: string; + abstract h: string; + protected abstract i: string; + public readonly j!: string; + + constructor() { + super(); + } +} + +function getPropModifier(name: string) { + const type = getClassType(SubCls); + return type.properties[name].modifiers; +} + +function matchModifiers(propName: string, expected: Types.ModifierFlags[]) { + expect({ + name: propName, + modifiers: getPropModifier(propName) + }).toEqual({ + name: propName, + modifiers: expected + }); +} + +describe("class properties modifiers", () => { + it("matches modifiers", () => { + matchModifiers("a", [Types.ModifierFlags.None]); + matchModifiers("b", [Types.ModifierFlags.Public]); + matchModifiers("c", [Types.ModifierFlags.Protected]); + matchModifiers("d", [Types.ModifierFlags.Private]); + matchModifiers("e", [Types.ModifierFlags.None, Types.ModifierFlags.Readonly]); + matchModifiers("f", [Types.ModifierFlags.None, Types.ModifierFlags.Override]); + matchModifiers("g", [Types.ModifierFlags.Protected, Types.ModifierFlags.Readonly, Types.ModifierFlags.Override]); + matchModifiers("h", [Types.ModifierFlags.None, Types.ModifierFlags.Abstract]); + matchModifiers("i", [Types.ModifierFlags.Protected, Types.ModifierFlags.Abstract]); + matchModifiers("j", [Types.ModifierFlags.Public, Types.ModifierFlags.Readonly]); + }); +}); From 3e269f06dda24931f0f371af130c5853db16fd52 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sat, 30 Dec 2023 15:36:40 -0300 Subject: [PATCH 5/9] Add hasModifier function --- packages/tsruntime/src/runtime/hasModifier.ts | 8 ++++++++ packages/tsruntime/src/runtime/index.ts | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 packages/tsruntime/src/runtime/hasModifier.ts diff --git a/packages/tsruntime/src/runtime/hasModifier.ts b/packages/tsruntime/src/runtime/hasModifier.ts new file mode 100644 index 0000000..62a0c43 --- /dev/null +++ b/packages/tsruntime/src/runtime/hasModifier.ts @@ -0,0 +1,8 @@ +import { ModifierFlags } from './publicTypes'; + +export const hasModifier = (type: { modifiers: number }, modifier: ModifierFlags) => { + if (modifier === type.modifiers) { + return true; + } + return !!(type.modifiers & modifier); +} diff --git a/packages/tsruntime/src/runtime/index.ts b/packages/tsruntime/src/runtime/index.ts index 28c5e0c..3bb9425 100644 --- a/packages/tsruntime/src/runtime/index.ts +++ b/packages/tsruntime/src/runtime/index.ts @@ -1,6 +1,7 @@ export * from './reflect' export * from './classUtils' export * from './common' +export * from './hasModifier' import * as Types from './publicTypes'; -export {Types} \ No newline at end of file +export {Types} From 81bec3b02eb971181d3328843ac81ffa26253553 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sat, 30 Dec 2023 15:39:26 -0300 Subject: [PATCH 6/9] Remove ModifierFlags import from typescript --- packages/tsruntime/src/runtime/publicTypes.ts | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/tsruntime/src/runtime/publicTypes.ts b/packages/tsruntime/src/runtime/publicTypes.ts index c935ec7..49fb480 100644 --- a/packages/tsruntime/src/runtime/publicTypes.ts +++ b/packages/tsruntime/src/runtime/publicTypes.ts @@ -1,6 +1,32 @@ -import { ModifierFlags } from "typescript"; - -export { ModifierFlags } from "typescript"; +export enum ModifierFlags { + None = 0, + Public = 1, + Private = 2, + Protected = 4, + Readonly = 8, + Override = 16, + Export = 32, + Abstract = 64, + Ambient = 128, + Static = 256, + Accessor = 512, + Async = 1024, + Default = 2048, + Const = 4096, + In = 8192, + Out = 16384, + Decorator = 32768, + Deprecated = 65536, + HasComputedJSDocModifiers = 268435456, + HasComputedFlags = 536870912, + AccessibilityModifier = 7, + ParameterPropertyModifier = 31, + NonPublicAccessibilityModifier = 6, + TypeScriptModifier = 28895, + ExportDefault = 2080, + All = 131071, + Modifier = 98303, +} export enum TypeKind { Any = 1, From 0e908899479c8532168dd62bb56f10204787975a Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sat, 30 Dec 2023 15:57:58 -0300 Subject: [PATCH 7/9] Undo modifiers as list --- .../tsruntime/src/transform/makeLiteral.ts | 12 ++--- packages/tsruntime/src/transform/reflect.ts | 51 +------------------ packages/tsruntime/src/transform/types.ts | 4 +- 3 files changed, 8 insertions(+), 59 deletions(-) diff --git a/packages/tsruntime/src/transform/makeLiteral.ts b/packages/tsruntime/src/transform/makeLiteral.ts index e6193fc..5e035c6 100644 --- a/packages/tsruntime/src/transform/makeLiteral.ts +++ b/packages/tsruntime/src/transform/makeLiteral.ts @@ -15,7 +15,7 @@ function getExpressionForPropertyName(name: ts.PropertyName) { //copied from typ } -export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags[]): ts.ObjectLiteralExpression { +export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags): ts.ObjectLiteralExpression { const assigns = [] const kindAssign = ts.factory.createPropertyAssignment("kind", ts.factory.createNumericLiteral(type.kind)) const kindAssignComment = ts.addSyntheticTrailingComment(kindAssign, ts.SyntaxKind.MultiLineCommentTrivia, TypeKind[type.kind], false) @@ -25,12 +25,10 @@ export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags[]) assigns.push(ts.factory.createPropertyAssignment("initializer", type.initializer)) } - if (Array.isArray(modifiers)) { + if (typeof modifiers !== 'undefined') { assigns.push(ts.factory.createPropertyAssignment( "modifiers", - ts.factory.createArrayLiteralExpression( - modifiers.map(mod => ts.factory.createNumericLiteral(mod)) - ) + ts.factory.createNumericLiteral(modifiers) )); } @@ -61,9 +59,7 @@ export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags[]) ts.factory.createPropertyAssignment("name", ts.factory.createStringLiteral(name)), ts.factory.createPropertyAssignment( "modifiers", - ts.factory.createArrayLiteralExpression( - modifiers.map(mod => ts.factory.createNumericLiteral(mod)) - ), + ts.factory.createNumericLiteral(modifiers), ), ts.factory.createPropertyAssignment("type", makeLiteral(type)), ])) diff --git a/packages/tsruntime/src/transform/reflect.ts b/packages/tsruntime/src/transform/reflect.ts index 9dd14c2..582f36f 100644 --- a/packages/tsruntime/src/transform/reflect.ts +++ b/packages/tsruntime/src/transform/reflect.ts @@ -55,11 +55,6 @@ namespace Normalizers { } export function getReflect(ctx: Ctx) { - const accessModifiers = [ - ts.ModifierFlags.Private, - ts.ModifierFlags.Protected, - ts.ModifierFlags.Public, - ]; function serializeUnion(type: ts.UnionType): ReflectedType { const nestedTypes = type.types.map(t => reflectType(t)); const normalizedTypes = Normalizers.normalizeUnion(nestedTypes); @@ -146,15 +141,7 @@ export function getReflect(ctx: Ctx) { const decl = sym.declarations![0]; const type = ctx.checker.getTypeOfSymbolAtLocation(sym, ctx.node); const serializedType = reflectType(type); - const modifiers = getModifiersFromDeclaration(decl, [ - ts.ModifierFlags.Private, - ts.ModifierFlags.Protected, - ts.ModifierFlags.Public, - ts.ModifierFlags.Readonly, - ts.ModifierFlags.Override, - ts.ModifierFlags.Static, - ts.ModifierFlags.Abstract, - ]); + const modifiers = ts.getCombinedModifierFlags(decl); const name = getPropertyName(sym); const initializer = ts.isPropertyDeclaration(sym.valueDeclaration!) @@ -171,13 +158,7 @@ export function getReflect(ctx: Ctx) { function serializeConstructorParameter(param: ts.Symbol): ConstructorParameter { const decl = param.declarations![0]; const type = reflectType(ctx.checker.getTypeOfSymbolAtLocation(param, decl)); - const modifiers = getModifiersFromDeclaration(decl, [ - ts.ModifierFlags.Private, - ts.ModifierFlags.Protected, - ts.ModifierFlags.Public, - ts.ModifierFlags.Readonly, - ts.ModifierFlags.Override, - ]); + const modifiers = ts.getCombinedModifierFlags(decl); const initializer = param.valueDeclaration && ts.isParameter(param.valueDeclaration) ? serializeInitializer(param.valueDeclaration) @@ -247,34 +228,6 @@ export function getReflect(ctx: Ctx) { // return { kind: TypeKind.Unknown2 }; } - function getModifiersFromDeclaration(decl: ts.Declaration, includesModifiers: ts.ModifierFlags[] = []) { - const modifierFlags = ts.getCombinedModifierFlags(decl); - const modifiers = modifierFlags === 0 - ? [ts.ModifierFlags.None] - : getModifiersByBruteForce(modifierFlags).filter(mod => includesModifiers.length === 0 || includesModifiers.includes(mod)); - - if (!modifiers.some(mod => accessModifiers.includes(mod)) && !modifiers.includes(ts.ModifierFlags.None)) { - modifiers.push(ts.ModifierFlags.None); - } - return modifiers.sort((a, b) => Number(a) - Number(b)); - } - - function getModifiersByBruteForce(modifierFlags: ts.ModifierFlags) { - const modifiers = []; - const modifiersToCheck = Object - .keys(ts.ModifierFlags) - .filter(k => isNaN(Number(k))) - .map(k => ts.ModifierFlags[k as keyof typeof ts.ModifierFlags]); - - for (const mod of modifiersToCheck) { - if (modifierFlags & mod) { - modifiers.push(mod); - } - } - - return modifiers; - } - function reflectType(type: ts.Type): ReflectedType { if (type.flags & ts.TypeFlags.Any) { return { kind: TypeKind.Any }; diff --git a/packages/tsruntime/src/transform/types.ts b/packages/tsruntime/src/transform/types.ts index 454e828..a8c2850 100644 --- a/packages/tsruntime/src/transform/types.ts +++ b/packages/tsruntime/src/transform/types.ts @@ -59,7 +59,7 @@ type Override2 = Override // type Override2 = T extends {[key: string]: infer R} ? {[key: string]: R extends Types.ReflectedType ? ReflectedType : R}: T -type Properties = Array<{ name: ts.PropertyName; type: ReflectedType; modifiers: Types.ModifierFlags[] }>; +type Properties = Array<{ name: ts.PropertyName; type: ReflectedType; modifiers: Types.ModifierFlags }>; export type ObjectType = Override< Types.ObjectType, { @@ -90,7 +90,7 @@ export type ReferenceType = Override< export interface ConstructorParameter { name: string; - modifiers: ts.ModifierFlags[]; + modifiers: ts.ModifierFlags; type: ReflectedType; } From 4172280bf3972a4cfcc88198d76a6e4e22eaa84a Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sat, 30 Dec 2023 15:58:38 -0300 Subject: [PATCH 8/9] Update tests --- .../tests/src/types/classConstructor.test.ts | 8 ++--- packages/tests/src/types/interfaces.test.ts | 4 +-- packages/tests/src/types/objectTypes.test.ts | 2 +- .../src/types/propertyInitializer.test.ts | 18 +++++------ .../tests/src/types/propertyModifiers.test.ts | 30 +++++++++++-------- packages/tests/src/types/transform.test.ts | 4 +-- 6 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/tests/src/types/classConstructor.test.ts b/packages/tests/src/types/classConstructor.test.ts index 07a4417..b26c76d 100644 --- a/packages/tests/src/types/classConstructor.test.ts +++ b/packages/tests/src/types/classConstructor.test.ts @@ -17,12 +17,12 @@ describe("Class Constructor", () => { parameters: [ { name: "foo", - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, type: {kind: Types.TypeKind.String}, }, { name: "bar", - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, type: {kind: Types.TypeKind.Number}, }, ], @@ -44,11 +44,11 @@ describe("Class Constructor", () => { parameters: [ { name: "foo", - modifiers: [Types.ModifierFlags.Public], + modifiers: Types.ModifierFlags.Public, }, { name: "bar", - modifiers: [Types.ModifierFlags.Private], + modifiers: Types.ModifierFlags.Private, }, ], }, diff --git a/packages/tests/src/types/interfaces.test.ts b/packages/tests/src/types/interfaces.test.ts index 20728f6..58b7296 100644 --- a/packages/tests/src/types/interfaces.test.ts +++ b/packages/tests/src/types/interfaces.test.ts @@ -25,7 +25,7 @@ interface IExtends extends IExtended { } -const stringType = {kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None]} +const stringType = {kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None} describe("interfaces", () => { @@ -42,7 +42,7 @@ describe("interfaces", () => { [constKey]: stringType, ['computed-string']: stringType, [uniqSymb]: stringType, - method: {kind: Types.TypeKind.Function, modifiers: [Types.ModifierFlags.None]} + method: {kind: Types.TypeKind.Function, modifiers: Types.ModifierFlags.None} } }); }); diff --git a/packages/tests/src/types/objectTypes.test.ts b/packages/tests/src/types/objectTypes.test.ts index e02b93c..257cf6b 100644 --- a/packages/tests/src/types/objectTypes.test.ts +++ b/packages/tests/src/types/objectTypes.test.ts @@ -6,7 +6,7 @@ const constKey = "some-key"; const uniqSymb = Symbol("some symb"); -const stringType = {kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None]} +const stringType = {kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None} type ObjectType = { key: string diff --git a/packages/tests/src/types/propertyInitializer.test.ts b/packages/tests/src/types/propertyInitializer.test.ts index 009b85d..22db578 100644 --- a/packages/tests/src/types/propertyInitializer.test.ts +++ b/packages/tests/src/types/propertyInitializer.test.ts @@ -40,17 +40,17 @@ function typeIsEqual(type: Types.ReflectedType, val: any) { describe("class properties initializers", () => { it("primitive types", () => { - typeIsEqual(getPropType("string"), { kind: TypeKind.String, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("string"), { kind: TypeKind.String, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("string"), 'string'); - typeIsEqual(getPropType("number"), { kind: TypeKind.Number, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("number"), { kind: TypeKind.Number, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("number"), 42); - typeIsEqual(getPropType("true"), { kind: TypeKind.Boolean, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("true"), { kind: TypeKind.Boolean, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("true"), true); - typeIsEqual(getPropType("false"), { kind: TypeKind.Boolean, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("false"), { kind: TypeKind.Boolean, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("false"), false); - typeIsEqual(getPropType("null"), { kind: TypeKind.Null, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("null"), { kind: TypeKind.Null, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("null"), null); - typeIsEqual(getPropType("undefined"), { kind: TypeKind.Undefined, modifiers: [Types.ModifierFlags.None] }); + typeIsEqual(getPropType("undefined"), { kind: TypeKind.Undefined, modifiers: Types.ModifierFlags.None }); initializerIsEqual(getPropType("undefined"), undefined); }); it("arrays", () => { @@ -60,7 +60,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: Array, - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, arguments: [{ kind: TypeKind.String }] }); initializerIsEqual(type, ["string"]); @@ -72,7 +72,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: Cls, - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, arguments: [] }); expect(type.initializer).not.toBeUndefined() @@ -84,7 +84,7 @@ describe("class properties initializers", () => { typeIsEqual(type, { kind: TypeKind.Reference, type: GenericCls, - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, arguments: [{ kind: Types.TypeKind.String }] }); expect(type.initializer).not.toBeUndefined() diff --git a/packages/tests/src/types/propertyModifiers.test.ts b/packages/tests/src/types/propertyModifiers.test.ts index 830c551..16a4645 100644 --- a/packages/tests/src/types/propertyModifiers.test.ts +++ b/packages/tests/src/types/propertyModifiers.test.ts @@ -1,4 +1,4 @@ -import {getClassType, Reflective, Types} from "tsruntime"; +import {getClassType, hasModifier, Reflective, Types} from "tsruntime"; class Cls { f!: string; @@ -25,19 +25,23 @@ abstract class SubCls extends Cls { } } -function getPropModifier(name: string) { +function getProperty(name: string) { const type = getClassType(SubCls); - return type.properties[name].modifiers; + return type.properties[name]; } function matchModifiers(propName: string, expected: Types.ModifierFlags[]) { - expect({ - name: propName, - modifiers: getPropModifier(propName) - }).toEqual({ - name: propName, - modifiers: expected - }); + for (const modifierFlag of expected) { + expect({ + name: propName, + modifierFlag, + hasModifier: hasModifier(getProperty(propName) as any as {modifiers: number}, modifierFlag) + }).toEqual({ + name: propName, + modifierFlag, + hasModifier: true + }); + } } describe("class properties modifiers", () => { @@ -46,10 +50,10 @@ describe("class properties modifiers", () => { matchModifiers("b", [Types.ModifierFlags.Public]); matchModifiers("c", [Types.ModifierFlags.Protected]); matchModifiers("d", [Types.ModifierFlags.Private]); - matchModifiers("e", [Types.ModifierFlags.None, Types.ModifierFlags.Readonly]); - matchModifiers("f", [Types.ModifierFlags.None, Types.ModifierFlags.Override]); + matchModifiers("e", [Types.ModifierFlags.Readonly]); + matchModifiers("f", [Types.ModifierFlags.Override]); matchModifiers("g", [Types.ModifierFlags.Protected, Types.ModifierFlags.Readonly, Types.ModifierFlags.Override]); - matchModifiers("h", [Types.ModifierFlags.None, Types.ModifierFlags.Abstract]); + matchModifiers("h", [Types.ModifierFlags.Abstract]); matchModifiers("i", [Types.ModifierFlags.Protected, Types.ModifierFlags.Abstract]); matchModifiers("j", [Types.ModifierFlags.Public, Types.ModifierFlags.Readonly]); }); diff --git a/packages/tests/src/types/transform.test.ts b/packages/tests/src/types/transform.test.ts index 2e0ef42..bd467db 100644 --- a/packages/tests/src/types/transform.test.ts +++ b/packages/tests/src/types/transform.test.ts @@ -39,7 +39,7 @@ describe("transform", () => { exported: { kind: Types.TypeKind.Reference, type: ExportedClass, - modifiers: [Types.ModifierFlags.None], + modifiers: Types.ModifierFlags.None, arguments: [] } }, @@ -71,7 +71,7 @@ describe("transform", () => { name: "TestClass", kind: Types.TypeKind.Class, properties: { - prop: { kind: Types.TypeKind.String, modifiers: [Types.ModifierFlags.None] } + prop: { kind: Types.TypeKind.String, modifiers: Types.ModifierFlags.None } }, constructors: [{modifiers: 0, parameters: []}], }); From 62c702895d00be251e6c6996f61cd07aa79aef85 Mon Sep 17 00:00:00 2001 From: Pedro Marcelo Date: Sat, 30 Dec 2023 16:47:07 -0300 Subject: [PATCH 9/9] Fix changes --- packages/tsruntime/src/transform/makeLiteral.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/tsruntime/src/transform/makeLiteral.ts b/packages/tsruntime/src/transform/makeLiteral.ts index 5e035c6..c3e1699 100644 --- a/packages/tsruntime/src/transform/makeLiteral.ts +++ b/packages/tsruntime/src/transform/makeLiteral.ts @@ -15,7 +15,7 @@ function getExpressionForPropertyName(name: ts.PropertyName) { //copied from typ } -export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags): ts.ObjectLiteralExpression { +export function makeLiteral(type: ReflectedType, modifier?: ts.ModifierFlags): ts.ObjectLiteralExpression { const assigns = [] const kindAssign = ts.factory.createPropertyAssignment("kind", ts.factory.createNumericLiteral(type.kind)) const kindAssignComment = ts.addSyntheticTrailingComment(kindAssign, ts.SyntaxKind.MultiLineCommentTrivia, TypeKind[type.kind], false) @@ -25,11 +25,8 @@ export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags): assigns.push(ts.factory.createPropertyAssignment("initializer", type.initializer)) } - if (typeof modifiers !== 'undefined') { - assigns.push(ts.factory.createPropertyAssignment( - "modifiers", - ts.factory.createNumericLiteral(modifiers) - )); + if (modifier !== undefined) { + assigns.push(ts.factory.createPropertyAssignment("modifiers", ts.factory.createNumericLiteral(modifier))); } switch (type.kind) { @@ -57,10 +54,7 @@ export function makeLiteral(type: ReflectedType, modifiers?: ts.ModifierFlags): ts.factory.createPropertyAssignment("parameters", ts.factory.createArrayLiteralExpression( parameters.map(({name, modifiers, type}) => ts.factory.createObjectLiteralExpression([ ts.factory.createPropertyAssignment("name", ts.factory.createStringLiteral(name)), - ts.factory.createPropertyAssignment( - "modifiers", - ts.factory.createNumericLiteral(modifiers), - ), + ts.factory.createPropertyAssignment("modifiers", ts.factory.createNumericLiteral(modifiers)), ts.factory.createPropertyAssignment("type", makeLiteral(type)), ])) ))