From 4e25faa0330d5cd7eb410560ea9d7308c3b69203 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Wed, 16 Dec 2020 18:35:15 +0100 Subject: [PATCH 01/19] Changed direct note references to IDs. --- src/importer/CapellaParser.ts | 2 +- src/importer/MusicXmlImporter.ts | 6 +-- src/model/Beat.ts | 8 +-- src/model/JsonConverter.ts | 87 +++++------------------------- src/model/Note.ts | 93 ++++++++++++++++++++++++-------- src/model/Score.ts | 14 +++++ 6 files changed, 105 insertions(+), 105 deletions(-) diff --git a/src/importer/CapellaParser.ts b/src/importer/CapellaParser.ts index e3b44a5f6..d8b986b1a 100644 --- a/src/importer/CapellaParser.ts +++ b/src/importer/CapellaParser.ts @@ -885,7 +885,7 @@ export class CapellaParser { } } else if (c.attributes.has('end') && this._tieStarts.length > 0 && !note.isTieDestination) { note.isTieDestination = true; - note.tieOrigin = this._tieStarts[0]; + note.tieOriginNoteId = this._tieStarts[0].id; this._tieStarts.splice(0, 1); this._tieStartIds.delete(note.id); } diff --git a/src/importer/MusicXmlImporter.ts b/src/importer/MusicXmlImporter.ts index bd47f226a..70725773f 100644 --- a/src/importer/MusicXmlImporter.ts +++ b/src/importer/MusicXmlImporter.ts @@ -805,7 +805,7 @@ export class MusicXmlImporter extends ScoreImporter { } } else if (element.getAttribute('type') === 'stop' && this._tieStarts.length > 0 && !note.isTieDestination) { note.isTieDestination = true; - note.tieOrigin = this._tieStarts[0]; + note.tieOriginNoteId = this._tieStarts[0].id; this._tieStarts.splice(0, 1); this._tieStartIds.delete(note.id); } @@ -849,8 +849,8 @@ export class MusicXmlImporter extends ScoreImporter { if (this._slurStarts.has(slurNumber)) { note.isSlurDestination = true; let slurStart: Note = this._slurStarts.get(slurNumber)!; - slurStart.slurDestination = note; - note.slurOrigin = note; + slurStart.slurDestinationNoteId = note.id; + note.slurOriginNoteId = note.id; } break; } diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 6494e5337..1e8637c33 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -747,12 +747,12 @@ export class Beat { // fix ties if(note.isTieOrigin) { - cloneNote.tieDestination = note.tieDestination!; - note.tieDestination!.tieOrigin = cloneNote; + cloneNote.tieDestinationNoteId = note.tieDestination!.id; + note.tieDestination!.tieOriginNoteId = cloneNote.id; } if(note.isTieDestination) { - cloneNote.tieOrigin = note.tieOrigin; - note.tieOrigin!.tieDestination = cloneNote; + cloneNote.tieOriginNoteId = note.tieOrigin ? note.tieOrigin.id : -1; + note.tieOrigin!.tieDestinationNoteId = cloneNote.id; } // if the note has a bend which is continued on the next note diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 5bcabba15..298895bce 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -22,15 +22,6 @@ import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; import { InstrumentArticulation } from './InstrumentArticulation'; -interface SerializedNote { - tieOriginId?: number; - tieDestinationId?: number; - slurOriginId?: number; - slurDestinationId?: number; - hammerPullOriginId?: number; - hammerPullDestinationId?: number; -} - /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further * JSON serialization. @@ -258,40 +249,15 @@ export class JsonConverter { Score.copyTo(score, score2); RenderStylesheet.copyTo(score.stylesheet, score2.stylesheet); - let allNotes: Map = new Map(); - let notesToLink: Note[] = []; - JsonConverter.jsObjectToMasterBars(score, score2); - JsonConverter.jsObjectToTracks(score, score2, allNotes, notesToLink); + JsonConverter.jsObjectToTracks(score, score2); - for (let note of notesToLink) { - let serializedNote = note as SerializedNote; - - if (serializedNote.tieOriginId !== undefined) { - note.tieOrigin = allNotes.get(serializedNote.tieOriginId)!; - } - if (serializedNote.tieDestinationId !== undefined) { - note.tieDestination = allNotes.get(serializedNote.tieDestinationId)!; - } - if (serializedNote.slurOriginId !== undefined) { - note.slurOrigin = allNotes.get(serializedNote.slurOriginId)!; - } - if (serializedNote.slurDestinationId !== undefined) { - note.slurDestination = allNotes.get(serializedNote.slurDestinationId)!; - } - if (serializedNote.hammerPullOriginId !== undefined) { - note.hammerPullOrigin = allNotes.get(serializedNote.hammerPullOriginId)!; - } - if (serializedNote.hammerPullDestinationId !== undefined) { - note.hammerPullDestination = allNotes.get(serializedNote.hammerPullDestinationId)!; - } - } score2.finish(settings ?? new Settings()); return score2; } - private static jsObjectToTracks(score: Score, score2: Score, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToTracks(score: Score, score2: Score) { for (let t: number = 0; t < score.tracks.length; t++) { let track: Track = score.tracks[t]; let track2: Track = new Track(); @@ -306,11 +272,11 @@ export class JsonConverter { track2.percussionArticulations.push(articulation2); } - JsonConverter.jsObjectToStaves(track, track2, allNotes, notesToLink); + JsonConverter.jsObjectToStaves(track, track2); } } - private static jsObjectToStaves(track: Track, track2: Track, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToStaves(track: Track, track2: Track) { for (let s: number = 0; s < track.staves.length; s++) { let staff: Staff = track.staves[s]; let staff2: Staff = track2.staves[s]; @@ -321,7 +287,7 @@ export class JsonConverter { staff2.addChord(chordId, chord2); }); - JsonConverter.jsObjectToBars(staff, staff2, allNotes, notesToLink); + JsonConverter.jsObjectToBars(staff, staff2); } } @@ -337,29 +303,29 @@ export class JsonConverter { } } - private static jsObjectToBars(staff: Staff, staff2: Staff, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToBars(staff: Staff, staff2: Staff) { for (let b: number = 0; b < staff.bars.length; b++) { let bar: Bar = staff.bars[b]; let bar2: Bar = new Bar(); Bar.copyTo(bar, bar2); staff2.addBar(bar2); - JsonConverter.jsObjectToVoices(bar, bar2, allNotes, notesToLink); + JsonConverter.jsObjectToVoices(bar, bar2); } } - private static jsObjectToVoices(bar: Bar, bar2: Bar, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToVoices(bar: Bar, bar2: Bar) { for (let v: number = 0; v < bar.voices.length; v++) { let voice: Voice = bar.voices[v]; let voice2: Voice = new Voice(); Voice.copyTo(voice, voice2); bar2.addVoice(voice2); - JsonConverter.jsObjectToBeats(voice, voice2, allNotes, notesToLink); + JsonConverter.jsObjectToBeats(voice, voice2); } } - private static jsObjectToBeats(voice: Voice, voice2: Voice, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToBeats(voice: Voice, voice2: Voice) { for (let bb: number = 0; bb < voice.beats.length; bb++) { let beat: Beat = voice.beats[bb]; let beat2: Beat = new Beat(); @@ -378,45 +344,16 @@ export class JsonConverter { beat2.addWhammyBarPoint(point); } - JsonConverter.jsObjectToNotes(beat, beat2, allNotes, notesToLink); + JsonConverter.jsObjectToNotes(beat, beat2); } } - private static jsObjectToNotes(beat: Beat, beat2: Beat, allNotes: Map, notesToLink: Note[]) { + private static jsObjectToNotes(beat: Beat, beat2: Beat) { for (let n: number = 0; n < beat.notes.length; n++) { let note: Note = beat.notes[n]; let note2: Note = new Note(); Note.copyTo(note, note2); beat2.addNote(note2); - allNotes.set(note2.id, note2); - - let serializedNote = note as SerializedNote; - let serializedNote2 = note2 as SerializedNote; - - if (serializedNote.tieOriginId !== undefined) { - serializedNote2.tieOriginId = serializedNote.tieOriginId; - notesToLink.push(note2); - } - if (serializedNote.tieDestinationId !== undefined) { - serializedNote2.tieDestinationId = serializedNote.tieDestinationId; - notesToLink.push(note2); - } - if (serializedNote.slurOriginId !== undefined) { - serializedNote2.slurOriginId = serializedNote.slurOriginId; - notesToLink.push(note2); - } - if (serializedNote.slurDestinationId !== undefined) { - serializedNote2.slurDestinationId = serializedNote.slurDestinationId; - notesToLink.push(note2); - } - if (serializedNote.hammerPullOriginId !== undefined) { - serializedNote2.hammerPullOriginId = serializedNote.hammerPullOriginId; - notesToLink.push(note2); - } - if (serializedNote.hammerPullDestinationId !== undefined) { - serializedNote2.hammerPullDestinationId = serializedNote.hammerPullDestinationId; - notesToLink.push(note2); - } for (let i: number = 0; i < note.bendPoints.length; i++) { let point: BendPoint = new BendPoint(0, 0); diff --git a/src/model/Note.ts b/src/model/Note.ts index ef7cb5b11..4229772e6 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -247,15 +247,29 @@ export class Note { return !!this.hammerPullOrigin; } + /** + * Gets the origin note id of the hammeron/pull-off of this note. + */ + public hammerPullOriginNoteId: number = -1; + /** * Gets the origin of the hammeron/pulloff of this note. */ - public hammerPullOrigin: Note | null = null; + public get hammerPullOrigin(): Note | null { + return this.hammerPullOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.hammerPullOriginNoteId); + } + + /** + * Gets the destination note id of the hammeron/pull-off of this note. + */ + public hammerPullDestinationNoteId: number = -1; /** * Gets the destination for the hammeron/pullof started by this note. */ - public hammerPullDestination: Note | null = null; + public get hammerPullDestination(): Note | null { + return this.hammerPullDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.hammerPullDestinationNoteId); + } public get isSlurOrigin(): boolean { return !!this.slurDestination; @@ -266,15 +280,30 @@ export class Note { */ public isSlurDestination: boolean = false; + + /** + * Gets the note id where the slur of this note starts. + */ + public slurOriginNoteId: number = -1; + /** * Gets or sets the note where the slur of this note starts. */ - public slurOrigin: Note | null = null; + public get slurOrigin(): Note | null { + return this.slurOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.slurOriginNoteId); + } + + /** + * Gets or sets the note id where the slur of this note ends. + */ + public slurDestinationNoteId: number = -1; /** * Gets or sets the note where the slur of this note ends. */ - public slurDestination: Note | null = null; + public get slurDestination(): Note | null { + return this.slurDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.slurDestinationNoteId); + } public get isHarmonic(): boolean { return this.harmonicType !== HarmonicType.None; @@ -350,15 +379,30 @@ export class Note { */ public vibrato: VibratoType = VibratoType.None; + + /** + * Gets the origin note id of the tied if this note is tied. + */ + public tieOriginNoteId: number = -1; + /** - * Gets or sets the origin of the tied if this note is tied. + * Gets the origin of the tied if this note is tied. */ - public tieOrigin: Note | null = null; + public get tieOrigin(): Note | null { + return this.tieOriginNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.tieOriginNoteId); + } /** - * Gets or sets the desination of the tie. + * Gets the desination note id of the tie. */ - public tieDestination: Note | null = null; + public tieDestinationNoteId: number = -1; + + /** + * Gets the desination of the tie. + */ + public get tieDestination(): Note | null { + return this.tieDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.tieDestinationNoteId); + } /** * Gets or sets whether this note is ends a tied note. @@ -366,7 +410,7 @@ export class Note { public isTieDestination: boolean = false; public get isTieOrigin(): boolean { - return !!this.tieDestination; + return this.tieDestinationNoteId !== -1; } /** @@ -710,12 +754,12 @@ export class Note { } // set hammeron/pulloffs if (this.isHammerPullOrigin) { - this.hammerPullDestination = Note.findHammerPullDestination(this); - - if (!this.hammerPullDestination) { + let hammerPullDestination = Note.findHammerPullDestination(this); + if (!hammerPullDestination) { this.isHammerPullOrigin = false; } else { - this.hammerPullDestination.hammerPullOrigin = this; + this.hammerPullDestinationNoteId = hammerPullDestination.id; + hammerPullDestination.hammerPullOriginNoteId = this.id; } } // set slides @@ -751,7 +795,7 @@ export class Note { // try to detect what kind of bend was used and cleans unneeded points if required // Guitar Pro 6 and above (gpif.xml) uses exactly 4 points to define all bends if (this.bendPoints.length > 0 && this.bendType === BendType.Custom) { - let isContinuedBend: boolean = (this.isContinuedBend = !!this.tieOrigin && this.tieOrigin.hasBend); + let isContinuedBend: boolean = (this.isContinuedBend = this.isTieDestination && this.tieOrigin!.hasBend); if (this.bendPoints.length === 4) { let origin: BendPoint = this.bendPoints[0]; let middle1: BendPoint = this.bendPoints[1]; @@ -927,22 +971,27 @@ export class Note { } public chain() { + this.beat.voice.bar.staff.track.score.registerNote(this); if (!this.isTieDestination) { return; } - if (!this.tieOrigin) { - this.tieOrigin = Note.findTieOrigin(this); + let tieOrigin: Note | null; + if (this.tieOriginNoteId === -1) { + tieOrigin = Note.findTieOrigin(this); + this.tieOriginNoteId = tieOrigin ? tieOrigin.id : -1; + } else { + tieOrigin = this.tieOrigin; } - if (!this.tieOrigin) { + if (!tieOrigin) { this.isTieDestination = false; } else { - this.tieOrigin.tieDestination = this; - this.fret = this.tieOrigin.fret; - this.octave = this.tieOrigin.octave; - this.tone = this.tieOrigin.tone; - if (this.tieOrigin.hasBend) { + tieOrigin.tieDestinationNoteId = this.id; + this.fret = tieOrigin.fret; + this.octave = tieOrigin.octave; + this.tone = tieOrigin.tone; + if (tieOrigin.hasBend) { this.bendOrigin = this.tieOrigin; } } diff --git a/src/model/Score.ts b/src/model/Score.ts index bc3bc5a31..f476fbdda 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -3,6 +3,7 @@ import { RenderStylesheet } from '@src/model/RenderStylesheet'; import { RepeatGroup } from '@src/model/RepeatGroup'; import { Track } from '@src/model/Track'; import { Settings } from '@src/Settings'; +import { Note } from './Note'; /** * The score is the root node of the complete @@ -10,6 +11,7 @@ import { Settings } from '@src/Settings'; * a song and stores the sub components. */ export class Score { + private _noteByIdLookup: Map = new Map(); private _currentRepeatGroup: RepeatGroup = new RepeatGroup(); /** @@ -140,8 +142,20 @@ export class Score { } public finish(settings: Settings): void { + this._noteByIdLookup.clear(); + for (let i: number = 0, j: number = this.tracks.length; i < j; i++) { this.tracks[i].finish(settings); } } + + public registerNote(note: Note) { + this._noteByIdLookup.set(note.id, note); + } + + public getNoteById(noteId: number): Note | null { + return this._noteByIdLookup.has(noteId) + ? this._noteByIdLookup.get(noteId)! + : null; + } } From b7bf36e1afdf04d8b5d7e35e51c913b90ee7603d Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Wed, 16 Dec 2020 21:28:34 +0100 Subject: [PATCH 02/19] Autogenerate CopyTo --- .vscode/launch.json | 16 + src.compiler/BuilderHelpers.ts | 76 ++++ src.compiler/CloneBuilder.ts | 340 ++++++++++++++ src.compiler/JsonSerializationBuilder.ts | 557 +++++++++++------------ src/Settings.ts | 2 +- src/model/Automation.ts | 15 +- src/model/Bar.ts | 8 - src/model/Beat.ts | 92 ++-- src/model/BendPoint.ts | 12 +- src/model/Chord.ts | 10 - src/model/Fermata.ts | 5 - src/model/Font.ts | 4 - src/model/InstrumentArticulation.ts | 10 - src/model/JsonConverter.ts | 336 +------------- src/model/MasterBar.ts | 16 - src/model/Note.ts | 70 +-- src/model/PlaybackInformation.ts | 11 - src/model/RenderStylesheet.ts | 4 - src/model/Score.ts | 15 - src/model/Section.ts | 5 - src/model/Staff.ts | 12 - src/model/Track.ts | 8 - src/model/Voice.ts | 5 - tsconfig.base.json | 3 + 24 files changed, 751 insertions(+), 881 deletions(-) create mode 100644 src.compiler/BuilderHelpers.ts create mode 100644 src.compiler/CloneBuilder.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 652070ee1..5b8126aeb 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { "name": "Launch C# Compiler", "type": "node", @@ -25,6 +26,21 @@ "env": { "TS_NODE_PROJECT": "tsconfig.build-csharp.json" } + }, + { + "name": "Launch JavaScript Compiler", + "type": "node", + "request": "launch", + "runtimeExecutable": "npm", + "windows": { + "runtimeExecutable": "npm.cmd" + }, + "runtimeArgs": [ + "run-script", + "build", + "--inspect-brk=5858" + ], + "port": 5858 } ] } \ No newline at end of file diff --git a/src.compiler/BuilderHelpers.ts b/src.compiler/BuilderHelpers.ts new file mode 100644 index 000000000..04d225a26 --- /dev/null +++ b/src.compiler/BuilderHelpers.ts @@ -0,0 +1,76 @@ +import * as ts from 'typescript'; + +export function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNode) { + let isNullable = false; + let type: ts.Type | null = null; + if (ts.isUnionTypeNode(node)) { + for (const t of node.types) { + if (t.kind === ts.SyntaxKind.NullKeyword) { + isNullable = true; + } else if (ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword) { + isNullable = true; + } else if (type !== null) { + throw new Error('Multi union types on JSON settings not supported: ' + node.getSourceFile().fileName + ':' + node.getText()); + } else { + type = checker.getTypeAtLocation(t); + } + } + } else { + type = checker.getTypeAtLocation(node); + } + + return { + isNullable, + type + }; +} + + +export function isPrimitiveType(type: ts.Type) { + if (hasFlag(type, ts.TypeFlags.Number)) { + return true; + } + if (hasFlag(type, ts.TypeFlags.String)) { + return true; + } + if (hasFlag(type, ts.TypeFlags.Boolean)) { + return true; + } + if (hasFlag(type, ts.TypeFlags.BigInt)) { + return true; + } + if (hasFlag(type, ts.TypeFlags.Unknown)) { + return true; + } + + return isEnumType(type); +} + +export function isEnumType(type: ts.Type) { + // if for some reason this returns true... + if (hasFlag(type, ts.TypeFlags.Enum)) return true; + // it's not an enum type if it's an enum literal type + if (hasFlag(type, ts.TypeFlags.EnumLiteral) && !type.isUnion()) return false; + // get the symbol and check if its value declaration is an enum declaration + const symbol = type.getSymbol(); + if (!symbol) return false; + const { valueDeclaration } = symbol; + + return valueDeclaration && valueDeclaration.kind === ts.SyntaxKind.EnumDeclaration; +} + +export function wrapToNonNull(isNullableType: boolean, expr: ts.Expression, factory: ts.NodeFactory) { + return isNullableType ? expr : factory.createNonNullExpression(expr); +} + +export function isTypedArray(type: ts.Type) { + return type.symbol.members.has(ts.escapeLeadingUnderscores('slice')); +} + +export function hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean { + return (type.flags & flag) === flag; +} + +export function isMap(type: ts.Type): boolean { + return type.symbol.name === 'Map'; +} \ No newline at end of file diff --git a/src.compiler/CloneBuilder.ts b/src.compiler/CloneBuilder.ts new file mode 100644 index 000000000..fb23a8bb2 --- /dev/null +++ b/src.compiler/CloneBuilder.ts @@ -0,0 +1,340 @@ +import * as ts from 'typescript'; +import { getTypeWithNullableInfo } from './BuilderHelpers'; +import { isPrimitiveType } from './BuilderHelpers'; + +function isClonable(type: ts.Type): boolean { + if (!type.symbol) { + return false; + } + + const declaration = type.symbol.valueDeclaration; + if (declaration) { + return !!ts.getJSDocTags(declaration).find(t => t.tagName.text === 'cloneable'); + } + + return false; +} + +function unwrapArrayItemType(type: ts.Type, typeChecker: ts.TypeChecker): ts.Type | null { + if (type.symbol && type.symbol.name === 'Array') { + return (type as ts.TypeReference).typeArguments![0]; + } + + if (isPrimitiveType(type)) { + return null; + } + + if (type.isUnion()) { + const nonNullable = typeChecker.getNonNullableType(type); + return unwrapArrayItemType(nonNullable, typeChecker); + } + + return null; +} + +function generateClonePropertyStatements(prop: ts.PropertyDeclaration, typeChecker: ts.TypeChecker, factory: ts.NodeFactory): ts.Statement[] { + const propertyType = getTypeWithNullableInfo(typeChecker, prop.type); + + const propertyName = (prop.name as ts.Identifier).text; + + function assign(expr: ts.Expression) { + return [factory.createExpressionStatement( + factory.createAssignment( + factory.createPropertyAccessExpression( + factory.createIdentifier('clone'), + propertyName + ), + expr + ) + )]; + } + + const arrayItemType = unwrapArrayItemType(propertyType.type, typeChecker); + if (arrayItemType) { + if (isClonable(arrayItemType)) { + const collectionAddMethod = ts.getJSDocTags(prop) + .filter(t => t.tagName.text === 'clone_add') + .map(t => t.comment ?? "")[0]; + + const loopItems = [ + ...assign(factory.createArrayLiteralExpression(undefined)), + + factory.createForOfStatement( + undefined, + factory.createVariableDeclarationList( + [factory.createVariableDeclaration('i')], + ts.NodeFlags.Const + ), + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + factory.createExpressionStatement( + collectionAddMethod + // clone.addProp(i.clone()) + ? factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('clone'), + collectionAddMethod + ), + undefined, + [factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('i'), + 'clone' + ), + undefined, + [] + ), factory.createIdentifier('i')] + ) + // clone.prop.push(i.clone() + : factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('clone'), + propertyName + ), + 'push' + ), + undefined, + [factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('i'), + 'clone' + ), + undefined, + [] + )] + ) + ) + )]; + + if (propertyType.isNullable) { + // if(this.prop) { + // clone.prop = []; + // for(const i of this.prop) { clone.addProp(i.clone()); } + // // or + // for(const i of this.prop) { clone.prop.add(i.clone()); } + // } + return [factory.createIfStatement( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + factory.createBlock( + loopItems + ), + undefined + )]; + } else { + // clone.prop = []; + // for(const i of this.prop) { clone.addProp(i.clone()); } + // // or + // for(const i of this.prop) { clone.prop.add(i.clone()); } + return loopItems; + } + } else { + const sliceCall = + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + 'slice' + ), + undefined, + [] + ); + + if (propertyType.isNullable) { + return assign( + factory.createConditionalExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + factory.createToken(ts.SyntaxKind.QuestionToken), + sliceCall, + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() + ) + ); + } else { + // clone.prop = this.prop.splice() + return assign(sliceCall); + } + } + } else { + if (isClonable(propertyType.type)) { + // clone.prop = this.prop ? this.prop.clone() : null + return assign( + factory.createConditionalExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ), + 'clone' + ), + undefined, + [] + ), + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() + ) + ); + } else { + // clone.prop = this.prop + return assign( + factory.createPropertyAccessExpression( + factory.createThis(), + propertyName + ) + ); + } + } +} + +function generateCloneBody(classDeclaration: ts.ClassDeclaration, propertiesToSerialize: ts.PropertyDeclaration[], factory: ts.NodeFactory, typeChecker: ts.TypeChecker): ts.Block { + + const bodyStatements = propertiesToSerialize.reduce((stmts, prop) => { + stmts.push(...generateClonePropertyStatements(prop, typeChecker, factory)); + return stmts; + }, new Array()); + + return factory.createBlock([ + // const clone = new Type(); + factory.createVariableStatement( + [factory.createModifier(ts.SyntaxKind.ConstKeyword)], + [ + factory.createVariableDeclaration( + 'clone', + undefined, + undefined, + factory.createNewExpression(factory.createIdentifier(classDeclaration.name.text), [], []) + ) + ] + ), + ...bodyStatements, + // return json; + factory.createReturnStatement(factory.createIdentifier('clone')) + ]); +} + +function isCloneMember(propertyDeclaration: ts.PropertyDeclaration) { + if (propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.ReadonlyKeyword)) { + return false; + } + + if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.PublicKeyword)) { + return false; + } + + if (ts.getJSDocTags(propertyDeclaration).find(t => t.tagName.text === 'computed')) { + return false; + } + + return true; +} + +function rewriteClassForCloneable( + classDeclaration: ts.ClassDeclaration, + factory: ts.NodeFactory, + typeChecker: ts.TypeChecker +): ts.ClassDeclaration { + console.debug(`Rewriting ${classDeclaration.name.escapedText} for cloning`); + let cloneMethod: ts.MethodDeclaration = undefined; + let propertiesToSerialize: ts.PropertyDeclaration[] = []; + + var newMembers = []; + + // collect class state + classDeclaration.members.forEach(member => { + if (ts.isPropertyDeclaration(member)) { + const propertyDeclaration = member as ts.PropertyDeclaration; + if (isCloneMember(propertyDeclaration)) { + propertiesToSerialize.push(propertyDeclaration); + } + newMembers.push(member); + } else if (ts.isMethodDeclaration(member)) { + if (ts.isIdentifier(member.name)) { + const methodName = (member.name as ts.Identifier).escapedText; + switch (methodName) { + case 'clone': + cloneMethod = member; + break; + default: + newMembers.push(member); + break; + } + } + } else { + newMembers.push(member); + } + }); + + if (!cloneMethod) { + cloneMethod = factory.createMethodDeclaration( + undefined, + [factory.createModifier(ts.SyntaxKind.PublicKeyword)], + undefined, + 'clone', + undefined, + undefined, + [], + factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + undefined + ); + } + + cloneMethod = factory.updateMethodDeclaration( + cloneMethod, + cloneMethod.decorators, + cloneMethod.modifiers, + cloneMethod.asteriskToken, + cloneMethod.name, + cloneMethod.questionToken, + cloneMethod.typeParameters, + cloneMethod.parameters, + cloneMethod.type, + generateCloneBody(classDeclaration, propertiesToSerialize, factory, typeChecker) + ) + newMembers.push(cloneMethod); + + console.debug(`Rewriting ${classDeclaration.name.escapedText} done`); + + return factory.updateClassDeclaration( + classDeclaration, + classDeclaration.decorators, + classDeclaration.modifiers, + classDeclaration.name, + classDeclaration.typeParameters, + classDeclaration.heritageClauses, + newMembers + ); +} + +export default function (program: ts.Program) { + return (ctx: ts.TransformationContext) => { + return (sourceFile: ts.SourceFile) => { + function visitor(node: ts.Node): ts.Node { + if (ts.isClassDeclaration(node)) { + if (ts.getJSDocTags(node).find(t => t.tagName.text === 'cloneable')) { + return rewriteClassForCloneable(node, ctx.factory, program.getTypeChecker()); + } + } + + return node; + } + + return ts.visitEachChild(sourceFile, visitor, ctx); + }; + }; +} diff --git a/src.compiler/JsonSerializationBuilder.ts b/src.compiler/JsonSerializationBuilder.ts index f2e4e86d9..b688ef676 100644 --- a/src.compiler/JsonSerializationBuilder.ts +++ b/src.compiler/JsonSerializationBuilder.ts @@ -1,79 +1,16 @@ import * as ts from 'typescript'; +import { getTypeWithNullableInfo } from './BuilderHelpers'; +import { isPrimitiveType } from './BuilderHelpers'; +import { isEnumType } from './BuilderHelpers'; +import { wrapToNonNull } from './BuilderHelpers'; +import { isTypedArray } from './BuilderHelpers'; +import { isMap } from './BuilderHelpers'; +; interface JsonProperty { property: ts.PropertyDeclaration; jsonNames: string[]; } -function wrapToNonNull(isNullableType: boolean, expr: ts.Expression) { - return isNullableType ? expr : ts.createNonNullExpression(expr); -} - -function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNode) { - let isNullable = false; - let type: ts.Type | null = null; - if (ts.isUnionTypeNode(node)) { - for (const t of node.types) { - if (t.kind === ts.SyntaxKind.NullKeyword) { - isNullable = true; - } else if (ts.isLiteralTypeNode(t) && t.literal.kind === ts.SyntaxKind.NullKeyword) { - isNullable = true; - } else if (type !== null) { - throw new Error('Multi union types on JSON settings not supported: ' + node.getSourceFile().fileName + ':' + node.getText()); - } else { - type = checker.getTypeAtLocation(t); - } - } - } else { - type = checker.getTypeAtLocation(node); - } - - return { - isNullable, - type - }; -} - -function isPrimitiveType(type: ts.Type) { - if (hasFlag(type, ts.TypeFlags.Number)) { - return true; - } - if (hasFlag(type, ts.TypeFlags.String)) { - return true; - } - if (hasFlag(type, ts.TypeFlags.Boolean)) { - return true; - } - if (hasFlag(type, ts.TypeFlags.BigInt)) { - return true; - } - if (hasFlag(type, ts.TypeFlags.Unknown)) { - return true; - } - - return isEnumType(type); -} - -function isEnumType(type: ts.Type) { - // if for some reason this returns true... - if (hasFlag(type, ts.TypeFlags.Enum)) return true; - // it's not an enum type if it's an enum literal type - if (hasFlag(type, ts.TypeFlags.EnumLiteral) && !type.isUnion()) return false; - // get the symbol and check if its value declaration is an enum declaration - const symbol = type.getSymbol(); - if (!symbol) return false; - const { valueDeclaration } = symbol; - - return valueDeclaration && valueDeclaration.kind === ts.SyntaxKind.EnumDeclaration; -} - -function isTypedArray(type: ts.Type) { - return type.symbol.members.has(ts.escapeLeadingUnderscores('slice')); -} - -function hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean { - return (type.flags & flag) === flag; -} - function isImmutable(type: ts.Type): boolean { const declaration = type.symbol.valueDeclaration; if (declaration) { @@ -83,44 +20,43 @@ function isImmutable(type: ts.Type): boolean { return false; } -function isMap(type: ts.Type): boolean { - return type.symbol.name === 'Map'; -} - function generateToJsonBodyForClass( classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[] + propertiesToSerialize: JsonProperty[], + factory: ts.NodeFactory ): ts.Block { - return ts.createBlock([ + return factory.createBlock([ // const json:any = {}; - ts.createVariableStatement( - [ts.createModifier(ts.SyntaxKind.ConstKeyword)], + factory.createVariableStatement( + [factory.createModifier(ts.SyntaxKind.ConstKeyword)], [ - ts.createVariableDeclaration( + factory.createVariableDeclaration( 'json', - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - ts.createObjectLiteral() + undefined, + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + factory.createObjectLiteralExpression() ) ] ), // obj.fillToJson(json) - ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier('obj'), 'fillToJson'), + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('obj'), 'fillToJson'), [], - [ts.createIdentifier('json')] + [factory.createIdentifier('json')] ) ), // return json; - ts.createReturn(ts.createIdentifier('json')) + factory.createReturnStatement(factory.createIdentifier('json')) ]); } function generateFillToJsonBodyForClass( program: ts.Program, classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[] + propertiesToSerialize: JsonProperty[], + factory: ts.NodeFactory ): ts.Block { const statements: ts.Statement[] = []; @@ -129,14 +65,14 @@ function generateFillToJsonBodyForClass( const jsonName = prop.jsonNames.filter(n => n !== '')[0]; const accessJsonName = function (): ts.Expression { - return ts.createPropertyAccess(ts.createIdentifier('json'), jsonName); + return factory.createPropertyAccessExpression(factory.createIdentifier('json'), jsonName); }; const accessField = function (): ts.Expression { - return ts.createPropertyAccess(ts.createThis(), ts.createIdentifier(fieldName)); + return factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)); }; const assignToJsonName = function (value: ts.Expression): ts.Statement { - return ts.createExpressionStatement(ts.createAssignment(accessJsonName(), value)); + return factory.createExpressionStatement(factory.createAssignment(accessJsonName(), value)); }; if (jsonName) { @@ -149,18 +85,18 @@ function generateFillToJsonBodyForClass( if (type.isNullable) { statements.push( assignToJsonName( - ts.createConditional( + factory.createConditionalExpression( accessField(), - ts.createToken(ts.SyntaxKind.QuestionToken), - ts.createCall(ts.createPropertyAccess(accessField(), 'slice'), [], []), - ts.createToken(ts.SyntaxKind.ColonToken), - ts.createNull() + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() ) ) ); } else { statements.push( - assignToJsonName(ts.createCall(ts.createPropertyAccess(accessField(), 'slice'), [], [])) + assignToJsonName(factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) ); } } else if (isMap(type.type)) { @@ -172,35 +108,35 @@ function generateFillToJsonBodyForClass( // this.fieldName.forEach((val, key) => (json.jsonName as any)[key] = val)) statements.push( assignToJsonName( - ts.createAsExpression( - ts.createObjectLiteral(), - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createAsExpression( + factory.createObjectLiteralExpression(), + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ) ); statements.push( - ts.createExpressionStatement( - ts.createCall(ts.createPropertyAccess(accessField(), 'forEach'), undefined, [ - ts.createArrowFunction( + factory.createExpressionStatement( + factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'forEach'), undefined, [ + factory.createArrowFunction( undefined, undefined, [ - ts.createParameter(undefined, undefined, undefined, '$mv'), - ts.createParameter(undefined, undefined, undefined, '$mk') + factory.createParameterDeclaration(undefined, undefined, undefined, '$mv'), + factory.createParameterDeclaration(undefined, undefined, undefined, '$mk') ], undefined, - ts.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.createBlock([ - ts.createExpressionStatement( - ts.createAssignment( - ts.createElementAccess( - ts.createAsExpression( + factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + factory.createBlock([ + factory.createExpressionStatement( + factory.createAssignment( + factory.createElementAccessExpression( + factory.createAsExpression( accessJsonName(), - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ), - ts.createIdentifier('$mk') + factory.createIdentifier('$mk') ), - ts.createIdentifier('$mv') + factory.createIdentifier('$mv') ) ) ]) @@ -214,11 +150,12 @@ function generateFillToJsonBodyForClass( assignToJsonName( wrapToNonNull( type.isNullable, - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier(type.type.symbol.name), 'toJson'), + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'toJson'), [], [accessField()] - ) + ), + factory ) ) ); @@ -238,20 +175,20 @@ function generateFillToJsonBodyForClass( // } // this.field.fillToJson(json.jsonName) - let fillToJsonStatent: ts.Statement = ts.createExpressionStatement( - ts.createCall( + let fillToJsonStatent: ts.Statement = factory.createExpressionStatement( + factory.createCallExpression( // this.field.fillToJson - ts.createPropertyAccess(accessField(), 'fillToJson'), + factory.createPropertyAccessExpression(accessField(), 'fillToJson'), [], [accessJsonName()] ) ); if (type.isNullable) { - fillToJsonStatent = ts.createIf(accessField(), fillToJsonStatent); + fillToJsonStatent = factory.createIfStatement(accessField(), fillToJsonStatent); } statements.push( - ts.createIf( + factory.createIfStatement( // if(json.jsonName) accessJsonName(), // this.field.fillToJson(json.jsonName) @@ -260,13 +197,14 @@ function generateFillToJsonBodyForClass( assignToJsonName( wrapToNonNull( type.isNullable, - ts.createCall( + factory.createCallExpression( // TypeName.toJson - ts.createPropertyAccess(ts.createIdentifier(type.type.symbol.name), 'toJson'), + factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'toJson'), [], [accessField()] - ) - ) + ), + factory + ), ) ) ); @@ -274,30 +212,32 @@ function generateFillToJsonBodyForClass( } } - return ts.createBlock(statements); + return factory.createBlock(statements); } function generateFromJsonBodyForClass( classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[] + propertiesToSerialize: JsonProperty[], + factory: ts.NodeFactory ): ts.Block { const statements: ts.Statement[] = []; // if(!json) return null; statements.push( - ts.createIf( - ts.createPrefix(ts.SyntaxKind.ExclamationToken, ts.createIdentifier('json')), - ts.createReturn(ts.createNull()) + factory.createIfStatement( + factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, factory.createIdentifier('json')), + factory.createReturnStatement(factory.createNull()) ) ); // const obj = new Type(); statements.push( - ts.createVariableStatement( - [ts.createModifier(ts.SyntaxKind.ConstKeyword)], + factory.createVariableStatement( + [factory.createModifier(ts.SyntaxKind.ConstKeyword)], [ - ts.createVariableDeclaration( + factory.createVariableDeclaration( 'obj', undefined, - ts.createNew(ts.createIdentifier(classDeclaration.name.text), [], []) + undefined, + factory.createNewExpression(factory.createIdentifier(classDeclaration.name.text), [], []) ) ] ) @@ -305,11 +245,11 @@ function generateFromJsonBodyForClass( // obj.fillFromJson(json); statements.push( - ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier('obj'), 'fillFromJson'), + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('obj'), 'fillFromJson'), [], - [ts.createIdentifier('json')] + [factory.createIdentifier('json')] ) ) ); @@ -317,31 +257,32 @@ function generateFromJsonBodyForClass( // return obj; statements.push( // return json; - ts.createReturn(ts.createIdentifier('obj')) + factory.createReturnStatement(factory.createIdentifier('obj')) ); - return ts.createBlock(statements); + return factory.createBlock(statements); } function generateFillFromJsonBodyForClass( classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[] + propertiesToSerialize: JsonProperty[], + factory: ts.NodeFactory ): ts.Block { - return ts.createBlock([ - ts.createIf( + return factory.createBlock([ + factory.createIfStatement( // if(json) for($k in json) { this.setProperty($k.toLowerCase(), json[$k]) } - ts.createIdentifier('json'), - ts.createForIn( - ts.createVariableDeclarationList([ts.createVariableDeclaration('$k')], ts.NodeFlags.Const), - ts.createIdentifier('json'), - ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess(ts.createThis(), 'setProperty'), + factory.createIdentifier('json'), + factory.createForInStatement( + factory.createVariableDeclarationList([factory.createVariableDeclaration('$k')], ts.NodeFlags.Const), + factory.createIdentifier('json'), + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createThis(), 'setProperty'), [], [ // $k.toLowerCase(), - ts.createCall(ts.createPropertyAccess(ts.createIdentifier('$k'), 'toLowerCase'), [], []), + factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('$k'), 'toLowerCase'), [], []), // json[$k] - ts.createElementAccess(ts.createIdentifier('json'), ts.createIdentifier('$k')) + factory.createElementAccessExpression(factory.createIdentifier('json'), factory.createIdentifier('$k')) ] ) ) @@ -350,47 +291,47 @@ function generateFillFromJsonBodyForClass( ]); } -function createEnumMapping(value: string, type: ts.Type): ts.Expression { +function createEnumMapping(value: string, type: ts.Type, factory: ts.NodeFactory): ts.Expression { // isNan(parseInt(value)) ? Enum[Object.keys(Enum).find($k => $k.toLowerCase() === value.toLowerCase()] : parseInt(value) - return ts.createConditional( - ts.createCall(ts.createIdentifier('isNaN'), undefined, [ - ts.createCall(ts.createIdentifier('parseInt'), undefined, [ts.createIdentifier(value)]) + return factory.createConditionalExpression( + factory.createCallExpression(factory.createIdentifier('isNaN'), undefined, [ + factory.createCallExpression(factory.createIdentifier('parseInt'), undefined, [factory.createIdentifier(value)]) ]), - ts.createToken(ts.SyntaxKind.QuestionToken), - ts.createElementAccess( - ts.createIdentifier(type.symbol.name), - ts.createCall( + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createElementAccessExpression( + factory.createIdentifier(type.symbol.name), + factory.createCallExpression( // Object.keys(EnumName).find - ts.createPropertyAccess( + factory.createPropertyAccessExpression( // Object.keys(EnumName) - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier('Object'), 'keys'), + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('Object'), 'keys'), [], - [ts.createIdentifier(type.symbol.name)] + [factory.createIdentifier(type.symbol.name)] ), 'find' ), [], [ - ts.createArrowFunction( + factory.createArrowFunction( [], [], - [ts.createParameter(undefined, undefined, undefined, '$k')], + [factory.createParameterDeclaration(undefined, undefined, undefined, '$k')], undefined, - ts.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.createBinary( - ts.createCall( + factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + factory.createBinaryExpression( + factory.createCallExpression( // $.toLowerCase() - ts.createPropertyAccess(ts.createIdentifier('$k'), 'toLowerCase'), + factory.createPropertyAccessExpression(factory.createIdentifier('$k'), 'toLowerCase'), [], [] ), // === - ts.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), + factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), // value.toLowerCase() - ts.createCall( + factory.createCallExpression( // $.toLowerCase() - ts.createPropertyAccess(ts.createIdentifier(value), 'toLowerCase'), + factory.createPropertyAccessExpression(factory.createIdentifier(value), 'toLowerCase'), [], [] ) @@ -399,15 +340,16 @@ function createEnumMapping(value: string, type: ts.Type): ts.Expression { ] ) ), - ts.createToken(ts.SyntaxKind.ColonToken), - ts.createCall(ts.createIdentifier('parseInt'), undefined, [ts.createIdentifier(value)]) + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createCallExpression(factory.createIdentifier('parseInt'), undefined, [factory.createIdentifier(value)]) ); } function generateSetPropertyMethodBodyForClass( program: ts.Program, classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[] + propertiesToSerialize: JsonProperty[], + factory: ts.NodeFactory ): ts.Block { const statements: ts.Statement[] = []; const cases: ts.CaseOrDefaultClause[] = []; @@ -423,21 +365,21 @@ function generateSetPropertyMethodBodyForClass( const type = getTypeWithNullableInfo(typeChecker, prop.property.type); const assignField = function (expr: ts.Expression): ts.Statement { - return ts.createExpressionStatement( - ts.createAssignment(ts.createPropertyAccess(ts.createThis(), fieldName), expr) + return factory.createExpressionStatement( + factory.createAssignment(factory.createPropertyAccessExpression(factory.createThis(), fieldName), expr) ); }; if (isEnumType(type.type)) { // this.fieldName = enummapping // return true; - caseStatements.push(assignField(createEnumMapping('value', type.type))); - caseStatements.push(ts.createReturn(ts.createTrue())); + caseStatements.push(assignField(createEnumMapping('value', type.type, factory))); + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isPrimitiveType(type.type)) { // this.fieldName = value // return true; - caseStatements.push(assignField(ts.createIdentifier('value'))); - caseStatements.push(ts.createReturn(ts.createTrue())); + caseStatements.push(assignField(factory.createIdentifier('value'))); + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isTypedArray(type.type)) { // nullable: // this.fieldName = value ? value.slice() : null @@ -450,22 +392,22 @@ function generateSetPropertyMethodBodyForClass( if (type.isNullable) { caseStatements.push( assignField( - ts.createConditional( - ts.createIdentifier('value'), - ts.createToken(ts.SyntaxKind.QuestionToken), - ts.createCall(ts.createPropertyAccess(ts.createIdentifier('value'), 'slice'), [], []), - ts.createToken(ts.SyntaxKind.ColonToken), - ts.createNull() + factory.createConditionalExpression( + factory.createIdentifier('value'), + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], []), + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() ) ) ); } else { caseStatements.push( - assignField(ts.createCall(ts.createPropertyAccess(ts.createIdentifier('value'), 'slice'), [], [])) + assignField(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], [])) ); } - caseStatements.push(ts.createReturn(ts.createTrue())); + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isMap(type.type)) { // this.fieldName = new Map(); // for(let key in value) { @@ -478,37 +420,37 @@ function generateSetPropertyMethodBodyForClass( throw new Error('only Map maps are supported extend if needed!'); } - caseStatements.push(assignField(ts.createNew(ts.createIdentifier('Map'), undefined, []))); + caseStatements.push(assignField(factory.createNewExpression(factory.createIdentifier('Map'), undefined, []))); caseStatements.push( - ts.createForIn( - ts.createVariableDeclarationList( - [ts.createVariableDeclaration(ts.createIdentifier('$mk'), undefined, undefined)], + factory.createForInStatement( + factory.createVariableDeclarationList( + [factory.createVariableDeclaration(factory.createIdentifier('$mk'), undefined, undefined)], ts.NodeFlags.Let ), - ts.createIdentifier('value'), - ts.createIf( - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier('value'), 'hasOwnProperty'), + factory.createIdentifier('value'), + factory.createIfStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'hasOwnProperty'), undefined, - [ts.createIdentifier('$mk')] + [factory.createIdentifier('$mk')] ), - ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess( - ts.createPropertyAccess(ts.createThis(), ts.createIdentifier(fieldName)), - ts.createIdentifier('set') + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)), + factory.createIdentifier('set') ), undefined, [ - createEnumMapping('$mk', mapType.typeArguments![0]), - ts.createElementAccess(ts.createIdentifier('value'), ts.createIdentifier('$mk')) + createEnumMapping('$mk', mapType.typeArguments![0], factory), + factory.createElementAccessExpression(factory.createIdentifier('value'), factory.createIdentifier('$mk')) ] ) ) ) ) ); - caseStatements.push(ts.createReturn(ts.createTrue())); + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isImmutable(type.type)) { // this.fieldName = TypeName.fromJson(value)! // return true; @@ -516,116 +458,118 @@ function generateSetPropertyMethodBodyForClass( assignField( wrapToNonNull( type.isNullable, - ts.createCall( + factory.createCallExpression( // TypeName.fromJson - ts.createPropertyAccess(ts.createIdentifier(type.type.symbol.name), 'fromJson'), + factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'fromJson'), [], - [ts.createIdentifier('value')] - ) + [factory.createIdentifier('value')] + ), + factory ) ) ); - caseStatements.push(ts.createReturn(ts.createTrue())); + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else { // for complex types it is a bit more tricky // if the property matches exactly, we use fromJson // if the property starts with the field name, we try to set a sub-property - const jsonNameArray = ts.createArrayLiteral(jsonNames.map(n => ts.createStringLiteral(n))); + const jsonNameArray = factory.createArrayLiteralExpression(jsonNames.map(n => factory.createStringLiteral(n))); statements.push( - ts.createIf( + factory.createIfStatement( // if(["", "core"].indexOf(property) >= 0) - ts.createBinary( - ts.createCall( - ts.createPropertyAccess(jsonNameArray, 'indexOf'), + factory.createBinaryExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression(jsonNameArray, 'indexOf'), [], - [ts.createIdentifier('property')] + [factory.createIdentifier('property')] ), ts.SyntaxKind.GreaterThanEqualsToken, - ts.createNumericLiteral('0') + factory.createNumericLiteral('0') ), - ts.createBlock([ + factory.createBlock([ // if(this.field) { // this.field.fillFromJson(value); // } else { // this.field = TypeName.fromJson(value); // } // return true; - ts.createIf( - ts.createPropertyAccess(ts.createThis(), fieldName), - ts.createExpressionStatement( - ts.createCall( - ts.createPropertyAccess( - ts.createPropertyAccess(ts.createThis(), fieldName), + factory.createIfStatement( + factory.createPropertyAccessExpression(factory.createThis(), fieldName), + factory.createExpressionStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(factory.createThis(), fieldName), 'fillFromJson' ), [], - [ts.createIdentifier('value')] + [factory.createIdentifier('value')] ) ), assignField( wrapToNonNull( type.isNullable, - ts.createCall( + factory.createCallExpression( // TypeName.fromJson - ts.createPropertyAccess(ts.createIdentifier(type.type.symbol.name), 'fromJson'), + factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'fromJson'), [], - [ts.createIdentifier('value')] - ) + [factory.createIdentifier('value')] + ), + factory ) ) ), - ts.createReturn(ts.createTrue()) + factory.createReturnStatement(factory.createTrue()) ]), - ts.createBlock([ + factory.createBlock([ // for(const candidate of ["", "core"]) { // if(candidate.indexOf(property) === 0) { // if(!this.field) { this.field = new FieldType(); } // if(this.field.setProperty(property.substring(candidate.length), value)) return true; // } // } - ts.createForOf( + factory.createForOfStatement( undefined, - ts.createVariableDeclarationList([ts.createVariableDeclaration('$c')], ts.NodeFlags.Const), + factory.createVariableDeclarationList([factory.createVariableDeclaration('$c')], ts.NodeFlags.Const), jsonNameArray, - ts.createIf( - ts.createBinary( - ts.createCall( - ts.createPropertyAccess(ts.createIdentifier('property'), 'indexOf'), + factory.createIfStatement( + factory.createBinaryExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier('property'), 'indexOf'), [], - [ts.createIdentifier('$c')] + [factory.createIdentifier('$c')] ), ts.SyntaxKind.EqualsEqualsEqualsToken, - ts.createNumericLiteral('0') + factory.createNumericLiteral('0') ), - ts.createBlock([ - ts.createIf( - ts.createPrefix( + factory.createBlock([ + factory.createIfStatement( + factory.createPrefixUnaryExpression( ts.SyntaxKind.ExclamationToken, - ts.createPropertyAccess(ts.createThis(), fieldName) + factory.createPropertyAccessExpression(factory.createThis(), fieldName) ), - assignField(ts.createNew(ts.createIdentifier(type.type.symbol.name), [], [])) + assignField(factory.createNewExpression(factory.createIdentifier(type.type.symbol.name), [], [])) ), - ts.createIf( - ts.createCall( - ts.createPropertyAccess( - ts.createPropertyAccess(ts.createThis(), fieldName), + factory.createIfStatement( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(factory.createThis(), fieldName), 'setProperty' ), [], [ - ts.createCall( - ts.createPropertyAccess( - ts.createIdentifier('property'), + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('property'), 'substring' ), [], - [ts.createPropertyAccess(ts.createIdentifier('$c'), 'length')] + [factory.createPropertyAccessExpression(factory.createIdentifier('$c'), 'length')] ), - ts.createIdentifier('value') + factory.createIdentifier('value') ] ), - ts.createReturn(ts.createTrue()) + factory.createReturnStatement(factory.createTrue()) ) ]) ) @@ -638,8 +582,8 @@ function generateSetPropertyMethodBodyForClass( if (caseStatements.length > 0) { for (let i = 0; i < caseValues.length; i++) { cases.push( - ts.createCaseClause( - ts.createStringLiteral(caseValues[i]), + factory.createCaseClause( + factory.createStringLiteral(caseValues[i]), // last case gets the statements, others are fall through i < caseValues.length - 1 ? [] : caseStatements ) @@ -648,17 +592,18 @@ function generateSetPropertyMethodBodyForClass( } } - const switchExpr = ts.createSwitch(ts.createIdentifier('property'), ts.createCaseBlock(cases)); + const switchExpr = factory.createSwitchStatement(factory.createIdentifier('property'), factory.createCaseBlock(cases)); statements.unshift(switchExpr); - statements.push(ts.createReturn(ts.createFalse())); + statements.push(factory.createReturnStatement(factory.createFalse())); - return ts.createBlock(statements); + return factory.createBlock(statements); } function rewriteClassForJsonSerialization( program: ts.Program, classDeclaration: ts.ClassDeclaration, - sourceFile: ts.SourceFile + sourceFile: ts.SourceFile, + factory: ts.NodeFactory ): ts.ClassDeclaration { console.debug(`Rewriting ${classDeclaration.name.escapedText} for JSON serialization`); let toJsonMethod: ts.MethodDeclaration = undefined; @@ -718,138 +663,139 @@ function rewriteClassForJsonSerialization( }); if (!toJsonMethod) { - toJsonMethod = ts.createMethod( + toJsonMethod = factory.createMethodDeclaration( undefined, - [ts.createModifier(ts.SyntaxKind.PublicKeyword), ts.createModifier(ts.SyntaxKind.StaticKeyword)], + [factory.createModifier(ts.SyntaxKind.PublicKeyword), factory.createModifier(ts.SyntaxKind.StaticKeyword)], undefined, 'toJson', undefined, undefined, [ - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'obj', undefined, - ts.createTypeReferenceNode(classDeclaration.name, []) + factory.createTypeReferenceNode(classDeclaration.name, []) ) ], - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), undefined ); } if (!fillToJsonMethod) { - fillToJsonMethod = ts.createMethod( + fillToJsonMethod = factory.createMethodDeclaration( undefined, - [ts.createModifier(ts.SyntaxKind.PublicKeyword)], + [factory.createModifier(ts.SyntaxKind.PublicKeyword)], undefined, 'fillToJson', undefined, undefined, [ - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'json', undefined, - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ], - ts.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - ts.createBlock([ts.createThrow(ts.createStringLiteral('todo'))]) + factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) ); } if (!fromJsonMethod) { - fromJsonMethod = ts.createMethod( + fromJsonMethod = factory.createMethodDeclaration( undefined, - [ts.createModifier(ts.SyntaxKind.PublicKeyword), ts.createModifier(ts.SyntaxKind.StaticKeyword)], + [factory.createModifier(ts.SyntaxKind.PublicKeyword), factory.createModifier(ts.SyntaxKind.StaticKeyword)], undefined, 'fromJson', undefined, undefined, [ - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'json', undefined, - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ], - ts.createTypeReferenceNode(classDeclaration.name, []), - ts.createBlock([ts.createThrow(ts.createStringLiteral('todo'))]) + factory.createTypeReferenceNode(classDeclaration.name, []), + factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) ); } if (!fillFromJsonMethod) { - fillFromJsonMethod = ts.createMethod( + fillFromJsonMethod = factory.createMethodDeclaration( undefined, - [ts.createModifier(ts.SyntaxKind.PublicKeyword)], + [factory.createModifier(ts.SyntaxKind.PublicKeyword)], undefined, 'fillFromJson', undefined, undefined, [ - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'json', undefined, - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ], - ts.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - ts.createBlock([ts.createThrow(ts.createStringLiteral('todo'))]) + factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) ); } if (!setPropertyMethod) { - setPropertyMethod = ts.createMethod( + setPropertyMethod = factory.createMethodDeclaration( undefined, - [ts.createModifier(ts.SyntaxKind.PublicKeyword)], + [factory.createModifier(ts.SyntaxKind.PublicKeyword)], undefined, 'setProperty', undefined, undefined, [ - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'property', undefined, - ts.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) ), - ts.createParameter( + factory.createParameterDeclaration( undefined, undefined, undefined, 'value', undefined, - ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ], - ts.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), - ts.createBlock([ts.createThrow(ts.createStringLiteral('todo'))]) + factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), + factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) ); } function updateMethodBody( method: ts.MethodDeclaration, paramNames: string[], - body: ts.Block + body: ts.Block, + factory: ts.NodeFactory ): ts.MethodDeclaration { if (!method) { return; } const parameters = method.parameters.map((v, i) => - ts.createParameter( + factory.createParameterDeclaration( method.parameters[i].decorators, method.parameters[i].modifiers, method.parameters[i].dotDotDotToken, @@ -860,7 +806,7 @@ function rewriteClassForJsonSerialization( ) ); - return ts.updateMethod( + return factory.updateMethodDeclaration( method, method.decorators, method.modifiers, @@ -877,31 +823,36 @@ function rewriteClassForJsonSerialization( toJsonMethod = updateMethodBody( toJsonMethod, ['obj'], - generateToJsonBodyForClass(classDeclaration, propertiesToSerialize) + generateToJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + factory ); fillToJsonMethod = updateMethodBody( fillToJsonMethod, ['json'], - generateFillToJsonBodyForClass(program, classDeclaration, propertiesToSerialize) + generateFillToJsonBodyForClass(program, classDeclaration, propertiesToSerialize, factory), + factory ); fromJsonMethod = updateMethodBody( fromJsonMethod, ['json'], - generateFromJsonBodyForClass(classDeclaration, propertiesToSerialize) + generateFromJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + factory ); fillFromJsonMethod = updateMethodBody( fillFromJsonMethod, ['json'], - generateFillFromJsonBodyForClass(classDeclaration, propertiesToSerialize) + generateFillFromJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + factory ); setPropertyMethod = updateMethodBody( setPropertyMethod, ['property', 'value'], - generateSetPropertyMethodBodyForClass(program, classDeclaration, propertiesToSerialize) + generateSetPropertyMethodBodyForClass(program, classDeclaration, propertiesToSerialize, factory), + factory ); newMembers.push(toJsonMethod); @@ -912,7 +863,7 @@ function rewriteClassForJsonSerialization( console.debug(`Rewriting ${classDeclaration.name.escapedText} done`); - return ts.updateClassDeclaration( + return factory.updateClassDeclaration( classDeclaration, classDeclaration.decorators, classDeclaration.modifiers, @@ -929,7 +880,7 @@ export default function (program: ts.Program) { function visitor(node: ts.Node): ts.Node { if (ts.isClassDeclaration(node)) { if (ts.getJSDocTags(node).find(t => t.tagName.text === 'json')) { - return rewriteClassForJsonSerialization(program, node, sourceFile); + return rewriteClassForJsonSerialization(program, node, sourceFile, ctx.factory); } } diff --git a/src/Settings.ts b/src/Settings.ts index 0d1942ab1..3ea1c169d 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -36,7 +36,7 @@ export class Settings { * @target web */ public setProperty(property: string, value: any): boolean { - // dynamically implemented via macro + // dynamically implemented via AST transformer return false; } diff --git a/src/model/Automation.ts b/src/model/Automation.ts index 8f3b1d094..6aafccdb4 100644 --- a/src/model/Automation.ts +++ b/src/model/Automation.ts @@ -22,6 +22,7 @@ export enum AutomationType { /** * Automations are used to change the behaviour of a song. + * @cloneable */ export class Automation { /** @@ -66,18 +67,4 @@ export class Automation { automation.value = value * references[reference]; return automation; } - - public static copyTo(src: Automation, dst: Automation): void { - dst.isLinear = src.isLinear; - dst.ratioPosition = src.ratioPosition; - dst.text = src.text; - dst.type = src.type; - dst.value = src.value; - } - - public clone(): Automation { - let a: Automation = new Automation(); - Automation.copyTo(this, a); - return a; - } } diff --git a/src/model/Bar.ts b/src/model/Bar.ts index ab480c83a..df52f1a11 100644 --- a/src/model/Bar.ts +++ b/src/model/Bar.ts @@ -70,14 +70,6 @@ export class Bar { return true; } - public static copyTo(src: Bar, dst: Bar): void { - dst.id = src.id; - dst.index = src.index; - dst.clef = src.clef; - dst.clefOttava = src.clefOttava; - dst.simileMark = src.simileMark; - } - public addVoice(voice: Voice): void { voice.bar = this; voice.index = this.voices.length; diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 1e8637c33..f389abe16 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -43,12 +43,14 @@ export enum BeatBeamingMode { /** * A beat is a single block within a bar. A beat is a combination * of several notes played at the same time. + * @cloneable */ export class Beat { private static _globalBeatId: number = 0; /** * Gets or sets the unique id of this beat. + * @computed */ public id: number = Beat._globalBeatId++; @@ -59,11 +61,13 @@ export class Beat { /** * Gets or sets the previous beat within the whole song. + * @computed */ public previousBeat: Beat | null = null; /** * Gets or sets the next beat within the whole song. + * @computed */ public nextBeat: Beat | null = null; @@ -73,11 +77,13 @@ export class Beat { /** * Gets or sets the reference to the parent voice this beat belongs to. + * @computed */ public voice!: Voice; /** * Gets or sets the list of notes contained in this beat. + * @clone_add addCloneNote */ public notes: Note[] = []; @@ -124,21 +130,25 @@ export class Beat { /** * Gets or sets the note with the lowest pitch in this beat. Only visible notes are considered. + * @computed */ public minNote: Note | null = null; /** * Gets or sets the note with the highest pitch in this beat. Only visible notes are considered. + * @computed */ public maxNote: Note | null = null; /** * Gets or sets the note with the highest string number in this beat. Only visible notes are considered. + * @computed */ public maxStringNote: Note | null = null; /** * Gets or sets the note with the lowest string number in this beat. Only visible notes are considered. + * @computed */ public minStringNote: Note | null = null; @@ -233,6 +243,9 @@ export class Beat { ); } + /** + * @computed + */ public tupletGroup: TupletGroup | null = null; /** @@ -247,16 +260,19 @@ export class Beat { /** * Gets or sets the points defining the whammy bar usage. + * @clone_add addWhammyBarPoint */ public whammyBarPoints: BendPoint[] = []; /** * Gets or sets the highest point with for the highest whammy bar value. + * @computed */ public maxWhammyPoint: BendPoint | null = null; /** * Gets or sets the highest point with for the lowest whammy bar value. + * @computed */ public minWhammyPoint: BendPoint | null = null; @@ -358,8 +374,14 @@ export class Beat { return !!this.effectSlurOrigin; } + /** + * @computed + */ public effectSlurOrigin: Beat | null = null; + /** + * @computed + */ public effectSlurDestination: Beat | null = null; /** @@ -367,66 +389,6 @@ export class Beat { */ public beamingMode:BeatBeamingMode = BeatBeamingMode.Auto; - public static copyTo(src: Beat, dst: Beat): void { - dst.id = src.id; - dst.index = src.index; - dst.isEmpty = src.isEmpty; - dst.duration = src.duration; - dst.dots = src.dots; - dst.fadeIn = src.fadeIn; - if (src.lyrics) { - dst.lyrics = new Array(src.lyrics.length); - for (let i: number = 0; i < src.lyrics.length; i++) { - dst.lyrics[i] = src.lyrics[i]; - } - } - dst.pop = src.pop; - dst.hasRasgueado = src.hasRasgueado; - dst.slap = src.slap; - dst.tap = src.tap; - dst.text = src.text; - dst.brushType = src.brushType; - dst.brushDuration = src.brushDuration; - dst.tupletDenominator = src.tupletDenominator; - dst.tupletNumerator = src.tupletNumerator; - dst.vibrato = src.vibrato; - dst.chordId = src.chordId; - dst.graceType = src.graceType; - dst.pickStroke = src.pickStroke; - dst.tremoloSpeed = src.tremoloSpeed; - dst.crescendo = src.crescendo; - dst.displayStart = src.displayStart; - dst.displayDuration = src.displayDuration; - dst.playbackStart = src.playbackStart; - dst.playbackDuration = src.playbackDuration; - dst.dynamics = src.dynamics; - dst.isLegatoOrigin = src.isLegatoOrigin; - dst.invertBeamDirection = src.invertBeamDirection; - dst.preferredBeamDirection = src.preferredBeamDirection; - dst.whammyBarType = src.whammyBarType; - dst.isContinuedWhammy = src.isContinuedWhammy; - dst.ottava = src.ottava; - dst.whammyStyle = src.whammyStyle; - dst.beamingMode = src.beamingMode; - } - - public clone(): Beat { - let beat: Beat = new Beat(); - let id: number = beat.id; - for (const p of this.whammyBarPoints) { - beat.addWhammyBarPoint(p.clone()); - } - for (const n of this.notes) { - beat.addNoteInternal(n.clone(), n.realValue); - } - Beat.copyTo(this, beat); - for (const a of this.automations) { - beat.automations.push(a.clone()); - } - beat.id = id; - return beat; - } - public addWhammyBarPoint(point: BendPoint): void { this.whammyBarPoints.push(point); if (!this.maxWhammyPoint || point.value > this.maxWhammyPoint.value) { @@ -474,6 +436,11 @@ export class Beat { this.addNoteInternal(note, -1); } + // @ts-ignore + private addCloneNote(clone:Note, original:Note) { + this.addNoteInternal(clone, original.realValue); + } + private addNoteInternal(note: Note, realValue: number = -1): void { note.beat = this; note.index = this.notes.length; @@ -810,6 +777,11 @@ export class Beat { return null; } + public clone(): Beat { + // dynamically implemented via AST transformer + return new Beat(); + } + public chain() { for(const n of this.notes) { n.chain(); diff --git a/src/model/BendPoint.ts b/src/model/BendPoint.ts index e76b27a0b..d39d153b5 100644 --- a/src/model/BendPoint.ts +++ b/src/model/BendPoint.ts @@ -1,6 +1,7 @@ /** * A single point of a bending graph. Used to * describe WhammyBar and String Bending effects. + * @cloneable */ export class BendPoint { public static readonly MaxPosition: number = 60; @@ -25,15 +26,4 @@ export class BendPoint { this.offset = offset; this.value = value; } - - public static copyTo(src: BendPoint, dst: BendPoint): void { - dst.offset = src.offset; - dst.value = src.value; - } - - public clone(): BendPoint { - let point: BendPoint = new BendPoint(0, 0); - BendPoint.copyTo(this, point); - return point; - } } diff --git a/src/model/Chord.ts b/src/model/Chord.ts index 775cc6e6e..110434629 100644 --- a/src/model/Chord.ts +++ b/src/model/Chord.ts @@ -45,14 +45,4 @@ export class Chord { * Gets or sets whether the fingering is shown below the chord diagram. */ public showFingering: boolean = true; - - public static copyTo(src: Chord, dst: Chord): void { - dst.firstFret = src.firstFret; - dst.name = src.name; - dst.strings = src.strings.slice(0); - dst.barreFrets = src.barreFrets.slice(0); - dst.showName = src.showName; - dst.showDiagram = src.showDiagram; - dst.showFingering = src.showFingering; - } } diff --git a/src/model/Fermata.ts b/src/model/Fermata.ts index c95d17307..fb1c98916 100644 --- a/src/model/Fermata.ts +++ b/src/model/Fermata.ts @@ -29,9 +29,4 @@ export class Fermata { * Gets or sets the actual lenght of the fermata. */ public length: number = 0; - - public static copyTo(src: Fermata, dst: Fermata): void { - dst.type = src.type; - dst.length = src.length; - } } diff --git a/src/model/Font.ts b/src/model/Font.ts index d6ca14cca..1504d87b3 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -59,10 +59,6 @@ export class Font { this._css = this.toCssString(1); } - public clone(): Font { - return new Font(this.family, this.size, this.style); - } - public toCssString(scale: number): string { if (!this._css || !(Math.abs(scale - this._cssScale) < 0.01)) { let buf: string = ''; diff --git a/src/model/InstrumentArticulation.ts b/src/model/InstrumentArticulation.ts index bd0eb7ba8..18a4aea2b 100644 --- a/src/model/InstrumentArticulation.ts +++ b/src/model/InstrumentArticulation.ts @@ -51,16 +51,6 @@ export class InstrumentArticulation { this.techniqueSymbolPlacement = techniqueSymbolPlacement; } - public static copyTo(src: any, dst: InstrumentArticulation) { - dst.outputMidiNumber = src.outputMidiNumber; - dst.staffLine = src.staffLine; - dst.noteHeadDefault = src.noteHeadDefault; - dst.noteHeadHalf = src.noteHeadHalf; - dst.noteHeadWhole = src.noteHeadWhole; - dst.techniqueSymbol = src.techniqueSymbol; - dst.techniqueSymbolPlacement = src.techniqueSymbolPlacement; - } - public getSymbol(duration: Duration): MusicFontSymbol { switch (duration) { case Duration.Whole: diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 298895bce..8668cba9d 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -3,24 +3,9 @@ import { MetaNumberEvent } from '@src/midi/MetaNumberEvent'; import { MidiEvent } from '@src/midi/MidiEvent'; import { SystemExclusiveEvent } from '@src/midi/SystemExclusiveEvent'; import { MidiFile } from '@src/midi/MidiFile'; -import { Automation } from '@src/model/Automation'; -import { Bar } from '@src/model/Bar'; -import { Beat } from '@src/model/Beat'; -import { BendPoint } from '@src/model/BendPoint'; -import { Chord } from '@src/model/Chord'; -import { Fermata } from '@src/model/Fermata'; -import { MasterBar } from '@src/model/MasterBar'; -import { Note } from '@src/model/Note'; -import { PlaybackInformation } from '@src/model/PlaybackInformation'; -import { RenderStylesheet } from '@src/model/RenderStylesheet'; import { Score } from '@src/model/Score'; -import { Section } from '@src/model/Section'; -import { Staff } from '@src/model/Staff'; -import { Track } from '@src/model/Track'; -import { Voice } from '@src/model/Voice'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; -import { InstrumentArticulation } from './InstrumentArticulation'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further @@ -50,180 +35,8 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - let score2: Score = {} as any; - Score.copyTo(score, score2); - score2.masterBars = []; - score2.tracks = []; - - score2.stylesheet = {} as any; - RenderStylesheet.copyTo(score.stylesheet, score2.stylesheet); - - JsonConverter.masterBarsToJsObject(score, score2); - JsonConverter.tracksToJsObject(score, score2); - - return score2; - } - - private static tracksToJsObject(score: Score, score2: Score) { - for (let t: number = 0; t < score.tracks.length; t++) { - let track: Track = score.tracks[t]; - let track2: Track = {} as any; - track2.color = {} as any; - Track.copyTo(track, track2); - - track2.playbackInfo = {} as any; - PlaybackInformation.copyTo(track.playbackInfo, track2.playbackInfo); - - track2.percussionArticulations = []; - for(const articulation of track.percussionArticulations) { - const articulation2 = {} as any; - InstrumentArticulation.copyTo(articulation, articulation2); - track2.percussionArticulations.push(articulation2); - } - - JsonConverter.stavesToJsObject(track, track2); - score2.tracks.push(track2); - } - } - - private static stavesToJsObject(track: Track, track2: Track) { - track2.staves = []; - for (let s: number = 0; s < track.staves.length; s++) { - let staff: Staff = track.staves[s]; - let staff2: Staff = {} as any; - Staff.copyTo(staff, staff2); - staff2.chords = new Map(); - staff.chords.forEach((chord, chordId) => { - let chord2: Chord = {} as any; - Chord.copyTo(chord, chord2); - staff2.chords.set(chordId, chord2); - }); - - JsonConverter.barsToJsObject(staff, staff2); - track2.staves.push(staff2); - } - } - - private static barsToJsObject(staff: Staff, staff2: Staff) { - staff2.bars = []; - for (let b: number = 0; b < staff.bars.length; b++) { - let bar: Bar = staff.bars[b]; - let bar2: Bar = {} as any; - Bar.copyTo(bar, bar2); - - JsonConverter.voicesToJsObject(bar, bar2); - - staff2.bars.push(bar2); - } - } - - private static voicesToJsObject(bar: Bar, bar2: Bar) { - bar2.voices = []; - for (let v: number = 0; v < bar.voices.length; v++) { - let voice: Voice = bar.voices[v]; - let voice2: Voice = {} as any; - Voice.copyTo(voice, voice2); - - JsonConverter.beatsToJsObject(voice, voice2); - - bar2.voices.push(voice2); - } - } - - private static beatsToJsObject(voice: Voice, voice2: Voice) { - voice2.beats = []; - for (let bb: number = 0; bb < voice.beats.length; bb++) { - let beat: Beat = voice.beats[bb]; - let dynamicBeat2: any = {} as any; - let beat2: Beat = dynamicBeat2; - Beat.copyTo(beat, beat2); - - beat2.automations = []; - for (let a: number = 0; a < beat.automations.length; a++) { - let automation: Automation = {} as any; - Automation.copyTo(beat.automations[a], automation); - beat2.automations.push(automation); - } - - beat2.whammyBarPoints = []; - for (let i: number = 0; i < beat.whammyBarPoints.length; i++) { - let point: BendPoint = {} as any; - BendPoint.copyTo(beat.whammyBarPoints[i], point); - beat2.whammyBarPoints.push(point); - } - - JsonConverter.notesToJsObject(beat, beat2); - - voice2.beats.push(beat2); - } - } - - private static notesToJsObject(beat: Beat, beat2: Beat) { - beat2.notes = []; - for (let n: number = 0; n < beat.notes.length; n++) { - let note: Note = beat.notes[n]; - let dynamicNote2: any = {} as any; - let note2: Note = dynamicNote2; - Note.copyTo(note, note2); - - if (note.isTieDestination) { - dynamicNote2.tieOriginId = note.tieOrigin!.id; - } - - if (note.isTieOrigin) { - dynamicNote2.tieDestinationId = note.tieDestination!.id; - } - - if (note.isSlurDestination) { - dynamicNote2.slurOriginId = note.slurOrigin!.id; - } - - if (note.isSlurOrigin) { - dynamicNote2.slurDestinationId = note.slurDestination!.id; - } - - if (note.isHammerPullDestination) { - dynamicNote2.hammerPullOriginId = note.hammerPullOrigin!.id; - } - - if (note.isHammerPullOrigin) { - dynamicNote2.hammerPullDestinationId = note.hammerPullDestination!.id; - } - - note2.bendPoints = []; - for (let i: number = 0; i < note.bendPoints.length; i++) { - let point: BendPoint = {} as any; - BendPoint.copyTo(note.bendPoints[i], point); - note2.bendPoints.push(point); - } - beat2.notes.push(note2); - } - } - - private static masterBarsToJsObject(score: Score, score2: Score) { - for (let i: number = 0; i < score.masterBars.length; i++) { - let masterBar: MasterBar = score.masterBars[i]; - let masterBar2: MasterBar = {} as any; - MasterBar.copyTo(masterBar, masterBar2); - if (masterBar.tempoAutomation) { - masterBar2.tempoAutomation = {} as any; - Automation.copyTo(masterBar.tempoAutomation, masterBar2.tempoAutomation!); - } - - if (masterBar.section) { - masterBar2.section = {} as any; - Section.copyTo(masterBar.section, masterBar2.section!); - } - - masterBar2.fermata = new Map(); - masterBar.fermata.forEach((fermata, fermataId) => { - let fermata2: any = {} as any; - masterBar2.fermata.set(fermataId, fermata2); - Fermata.copyTo(fermata, fermata2); - }); - - score2.masterBars.push(masterBar2); - } + // TODO: new json serializer + return score; } /** @@ -233,161 +46,22 @@ export class JsonConverter { * @returns The converted score object. */ public static jsonToScore(json: string, settings?: Settings): Score { - return JsonConverter.jsObjectToScore(JsonConverter.jsObjectToScore(JSON.parse(json), settings), settings); + return JsonConverter.jsObjectToScore(settings); } /** * Converts the given JavaScript object into a score object. * @param jsObject The javascript object created via {@link Score} - * @param settings The settings to use during conversion. + * @pas The settings to use during conversion. * @returns The converted score object. */ - public static jsObjectToScore(jsObject: unknown, settings?: Settings): Score { - let score: Score = jsObject as Score; + public static jsObjectToScore(jsObject: any, settings?: Settings): Score { let score2: Score = new Score(); - Score.copyTo(score, score2); - RenderStylesheet.copyTo(score.stylesheet, score2.stylesheet); - - JsonConverter.jsObjectToMasterBars(score, score2); - - JsonConverter.jsObjectToTracks(score, score2); - score2.finish(settings ?? new Settings()); return score2; } - private static jsObjectToTracks(score: Score, score2: Score) { - for (let t: number = 0; t < score.tracks.length; t++) { - let track: Track = score.tracks[t]; - let track2: Track = new Track(); - track2.ensureStaveCount(track.staves.length); - Track.copyTo(track, track2); - score2.addTrack(track2); - PlaybackInformation.copyTo(track.playbackInfo, track2.playbackInfo); - - for(const articulation of track.percussionArticulations) { - const articulation2 = new InstrumentArticulation(); - InstrumentArticulation.copyTo(articulation, articulation2); - track2.percussionArticulations.push(articulation2); - } - - JsonConverter.jsObjectToStaves(track, track2); - } - } - - private static jsObjectToStaves(track: Track, track2: Track) { - for (let s: number = 0; s < track.staves.length; s++) { - let staff: Staff = track.staves[s]; - let staff2: Staff = track2.staves[s]; - Staff.copyTo(staff, staff2); - JsonConverter.jsObjectMapForEach(staff.chords, (chord, chordId) => { - let chord2: Chord = new Chord(); - Chord.copyTo(chord, chord2); - staff2.addChord(chordId, chord2); - }); - - JsonConverter.jsObjectToBars(staff, staff2); - } - } - - private static jsObjectMapForEach(obj: any, callback: (value: any, key: any) => void) { - if ('forEach' in obj) { - obj.forEach(callback); - } else { - for (let x in obj) { - if (obj.hasOwnProperty(x)) { - callback(obj[x], x); - } - } - } - } - - private static jsObjectToBars(staff: Staff, staff2: Staff) { - for (let b: number = 0; b < staff.bars.length; b++) { - let bar: Bar = staff.bars[b]; - let bar2: Bar = new Bar(); - Bar.copyTo(bar, bar2); - staff2.addBar(bar2); - - JsonConverter.jsObjectToVoices(bar, bar2); - } - } - - private static jsObjectToVoices(bar: Bar, bar2: Bar) { - for (let v: number = 0; v < bar.voices.length; v++) { - let voice: Voice = bar.voices[v]; - let voice2: Voice = new Voice(); - Voice.copyTo(voice, voice2); - bar2.addVoice(voice2); - - JsonConverter.jsObjectToBeats(voice, voice2); - } - } - - private static jsObjectToBeats(voice: Voice, voice2: Voice) { - for (let bb: number = 0; bb < voice.beats.length; bb++) { - let beat: Beat = voice.beats[bb]; - let beat2: Beat = new Beat(); - Beat.copyTo(beat, beat2); - voice2.addBeat(beat2); - - for (let a: number = 0; a < beat.automations.length; a++) { - let automation: Automation = new Automation(); - Automation.copyTo(beat.automations[a], automation); - beat2.automations.push(automation); - } - - for (let i: number = 0; i < beat.whammyBarPoints.length; i++) { - let point: BendPoint = new BendPoint(0, 0); - BendPoint.copyTo(beat.whammyBarPoints[i], point); - beat2.addWhammyBarPoint(point); - } - - JsonConverter.jsObjectToNotes(beat, beat2); - } - } - - private static jsObjectToNotes(beat: Beat, beat2: Beat) { - for (let n: number = 0; n < beat.notes.length; n++) { - let note: Note = beat.notes[n]; - let note2: Note = new Note(); - Note.copyTo(note, note2); - beat2.addNote(note2); - - for (let i: number = 0; i < note.bendPoints.length; i++) { - let point: BendPoint = new BendPoint(0, 0); - BendPoint.copyTo(note.bendPoints[i], point); - note2.addBendPoint(point); - } - } - } - - private static jsObjectToMasterBars(score: Score, score2: Score) { - for (let i: number = 0; i < score.masterBars.length; i++) { - let masterBar: MasterBar = score.masterBars[i]; - let masterBar2: MasterBar = new MasterBar(); - MasterBar.copyTo(masterBar, masterBar2); - - if (masterBar.tempoAutomation) { - masterBar2.tempoAutomation = new Automation(); - Automation.copyTo(masterBar.tempoAutomation, masterBar2.tempoAutomation); - } - - if (masterBar.section) { - masterBar2.section = new Section(); - Section.copyTo(masterBar.section, masterBar2.section); - } - - JsonConverter.jsObjectMapForEach(masterBar.fermata, (fermata, key) => { - let fermata2: Fermata = new Fermata(); - Fermata.copyTo(fermata, fermata2); - masterBar2.addFermata(typeof key === 'string' ? parseInt(key) : key, fermata2); - }); - score2.addMasterBar(masterBar2); - } - } - public static jsObjectToMidiFile(midi: any): MidiFile { let midi2: MidiFile = new MidiFile(); midi2.division = midi.division; diff --git a/src/model/MasterBar.ts b/src/model/MasterBar.ts index 1f19c061d..5e40f4d46 100644 --- a/src/model/MasterBar.ts +++ b/src/model/MasterBar.ts @@ -124,22 +124,6 @@ export class MasterBar { */ public isAnacrusis: boolean = false; - public static copyTo(src: MasterBar, dst: MasterBar): void { - dst.isAnacrusis = src.isAnacrusis; - dst.alternateEndings = src.alternateEndings; - dst.index = src.index; - dst.keySignature = src.keySignature; - dst.keySignatureType = src.keySignatureType; - dst.isDoubleBar = src.isDoubleBar; - dst.isRepeatStart = src.isRepeatStart; - dst.repeatCount = src.repeatCount; - dst.timeSignatureNumerator = src.timeSignatureNumerator; - dst.timeSignatureDenominator = src.timeSignatureDenominator; - dst.timeSignatureCommon = src.timeSignatureCommon; - dst.tripletFeel = src.tripletFeel; - dst.start = src.start; - } - /** * Calculates the time spent in this bar. (unit: midi ticks) */ diff --git a/src/model/Note.ts b/src/model/Note.ts index 4229772e6..138df14d9 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -25,11 +25,13 @@ import { PercussionMapper } from '@src/model/PercussionMapper'; * A note is a single played sound on a fretted instrument. * It consists of a fret offset and a string on which the note is played on. * It also can be modified by a lot of different effects. + * @cloneable */ export class Note { public static GlobalNoteId: number = 0; /** * Gets or sets the unique id of this note. + * @computed */ public id: number = Note.GlobalNoteId++; @@ -55,6 +57,7 @@ export class Note { /** * Gets or sets the note from which this note continues the bend. + * @computed */ public bendOrigin: Note | null = null; @@ -65,11 +68,13 @@ export class Note { /** * Gets or sets a list of the points defining the bend behavior. + * @clone_add addBendPoint */ public bendPoints: BendPoint[] = []; /** * Gets or sets the bend point with the highest bend value. + * @computed */ public maxBendPoint: BendPoint | null = null; @@ -267,7 +272,7 @@ export class Note { /** * Gets the destination for the hammeron/pullof started by this note. */ - public get hammerPullDestination(): Note | null { + public get hammerPullDestination(): Note | null { return this.hammerPullDestinationNoteId === -1 ? null : this.beat.voice.bar.staff.track.score.getNoteById(this.hammerPullDestinationNoteId); } @@ -331,6 +336,7 @@ export class Note { /** * Gets or sets the destination note for the let-ring effect. + * @computed */ public letRingDestination: Note | null = null; @@ -341,6 +347,7 @@ export class Note { /** * Gets or sets the destination note for the palm-mute effect. + * @computed */ public palmMuteDestination: Note | null = null; @@ -366,11 +373,13 @@ export class Note { /** * Gets or sets the target note for several slide types. + * @computed */ public slideTarget: Note | null = null; /** * Gets or sets the source note for several slide types. + * @computed */ public slideOrigin: Note | null = null; @@ -458,6 +467,7 @@ export class Note { /** * Gets or sets the reference to the parent beat to which this note belongs to. + * @computed */ public beat!: Beat; @@ -474,8 +484,14 @@ export class Note { return !!this.effectSlurOrigin; } + /** + * @computed + */ public effectSlurOrigin: Note | null = null; + /** + * @computed + */ public effectSlurDestination: Note | null = null; public get stringTuning(): number { @@ -664,53 +680,6 @@ export class Note { return false; } - public static copyTo(src: Note, dst: Note): void { - dst.id = src.id; - dst.accentuated = src.accentuated; - dst.fret = src.fret; - dst.string = src.string; - dst.harmonicValue = src.harmonicValue; - dst.harmonicType = src.harmonicType; - dst.isGhost = src.isGhost; - dst.isLetRing = src.isLetRing; - dst.isPalmMute = src.isPalmMute; - dst.isDead = src.isDead; - dst.isStaccato = src.isStaccato; - dst.slideInType = src.slideInType; - dst.slideOutType = src.slideOutType; - dst.vibrato = src.vibrato; - dst.isTieDestination = src.isTieDestination; - dst.isSlurDestination = src.isSlurDestination; - dst.isHammerPullOrigin = src.isHammerPullOrigin; - dst.leftHandFinger = src.leftHandFinger; - dst.rightHandFinger = src.rightHandFinger; - dst.isFingering = src.isFingering; - dst.trillValue = src.trillValue; - dst.trillSpeed = src.trillSpeed; - dst.durationPercent = src.durationPercent; - dst.accidentalMode = src.accidentalMode; - dst.dynamics = src.dynamics; - dst.octave = src.octave; - dst.tone = src.tone; - dst.percussionArticulation = src.percussionArticulation; - dst.bendType = src.bendType; - dst.bendStyle = src.bendStyle; - dst.isContinuedBend = src.isContinuedBend; - dst.isVisible = src.isVisible; - dst.isLeftHandTapped = src.isLeftHandTapped; - } - - public clone(): Note { - let n: Note = new Note(); - let id: number = n.id; - Note.copyTo(this, n); - for (let i: number = 0, j: number = this.bendPoints.length; i < j; i++) { - n.addBendPoint(this.bendPoints[i].clone()); - } - n.id = id; - return n; - } - public addBendPoint(point: BendPoint): void { this.bendPoints.push(point); if (!this.maxBendPoint || point.value > this.maxBendPoint.value) { @@ -996,4 +965,9 @@ export class Note { } } } + + public clone(): Note { + // dynamically implemented via AST transformer + return new Note(); + } } diff --git a/src/model/PlaybackInformation.ts b/src/model/PlaybackInformation.ts index 882599d46..7c0d10474 100644 --- a/src/model/PlaybackInformation.ts +++ b/src/model/PlaybackInformation.ts @@ -42,15 +42,4 @@ export class PlaybackInformation { * Gets or sets whether the track is playing alone. */ public isSolo: boolean = false; - - public static copyTo(src: PlaybackInformation, dst: PlaybackInformation): void { - dst.volume = src.volume; - dst.balance = src.balance; - dst.port = src.port; - dst.program = src.program; - dst.primaryChannel = src.primaryChannel; - dst.secondaryChannel = src.secondaryChannel; - dst.isMute = src.isMute; - dst.isSolo = src.isSolo; - } } diff --git a/src/model/RenderStylesheet.ts b/src/model/RenderStylesheet.ts index 7dae16ecb..45bb431cd 100644 --- a/src/model/RenderStylesheet.ts +++ b/src/model/RenderStylesheet.ts @@ -7,8 +7,4 @@ export class RenderStylesheet { * Gets or sets whether dynamics are hidden. */ public hideDynamics: boolean = false; - - public static copyTo(src: RenderStylesheet, dst: RenderStylesheet): void { - dst.hideDynamics = src.hideDynamics; - } } diff --git a/src/model/Score.ts b/src/model/Score.ts index f476fbdda..3d00ea573 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -89,21 +89,6 @@ export class Score { */ public stylesheet: RenderStylesheet = new RenderStylesheet(); - public static copyTo(src: Score, dst: Score): void { - dst.album = src.album; - dst.artist = src.artist; - dst.copyright = src.copyright; - dst.instructions = src.instructions; - dst.music = src.music; - dst.notices = src.notices; - dst.subTitle = src.subTitle; - dst.title = src.title; - dst.words = src.words; - dst.tab = src.tab; - dst.tempo = src.tempo; - dst.tempoLabel = src.tempoLabel; - } - public rebuildRepeatGroups(): void { let currentGroup: RepeatGroup = new RepeatGroup(); for (let bar of this.masterBars) { diff --git a/src/model/Section.ts b/src/model/Section.ts index fbebe9370..f5bf888ab 100644 --- a/src/model/Section.ts +++ b/src/model/Section.ts @@ -12,9 +12,4 @@ export class Section { * Gets or sets the descriptional text of this section. */ public text: string = ''; - - public static copyTo(src: Section, dst: Section): void { - dst.marker = src.marker; - dst.text = src.text; - } } diff --git a/src/model/Staff.ts b/src/model/Staff.ts index 5e74a5ed0..55d6b2528 100644 --- a/src/model/Staff.ts +++ b/src/model/Staff.ts @@ -82,18 +82,6 @@ export class Staff { */ public standardNotationLineCount: number = 5; - public static copyTo(src: Staff, dst: Staff): void { - dst.capo = src.capo; - dst.index = src.index; - dst.tuning = src.tuning.slice(); - dst.transpositionPitch = src.transpositionPitch; - dst.displayTranspositionPitch = src.displayTranspositionPitch; - dst.showStandardNotation = src.showStandardNotation; - dst.showTablature = src.showTablature; - dst.isPercussion = src.isPercussion; - dst.standardNotationLineCount = src.standardNotationLineCount; - } - public finish(settings: Settings): void { for (let i: number = 0, j: number = this.bars.length; i < j; i++) { this.bars[i].finish(settings); diff --git a/src/model/Track.ts b/src/model/Track.ts index 67beb2d76..e2efb1915 100644 --- a/src/model/Track.ts +++ b/src/model/Track.ts @@ -66,14 +66,6 @@ export class Track { this.staves.push(staff); } - public static copyTo(src: Track, dst: Track): void { - dst.name = src.name; - dst.shortName = src.shortName; - dst.index = src.index; - dst.color.raw = src.color.raw; - dst.color.rgba = src.color.rgba; - } - public finish(settings: Settings): void { if (!this.shortName) { this.shortName = this.name; diff --git a/src/model/Voice.ts b/src/model/Voice.ts index 77a211da5..8f903da81 100644 --- a/src/model/Voice.ts +++ b/src/model/Voice.ts @@ -32,11 +32,6 @@ export class Voice { */ public isEmpty: boolean = true; - public static copyTo(src: Voice, dst: Voice): void { - dst.index = src.index; - dst.isEmpty = src.isEmpty; - } - public insertBeat(after: Beat, newBeat: Beat): void { newBeat.nextBeat = after.nextBeat; if (newBeat.nextBeat) { diff --git a/tsconfig.base.json b/tsconfig.base.json index fb3744d17..fa4c85d68 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -37,6 +37,9 @@ { "transform": "./src.compiler/JsonSerializationBuilder.ts" }, + { + "transform": "./src.compiler/CloneBuilder.ts" + }, ] }, "include": [ From d3c26eb97846df8b86665ae335fc7b0a14cd96e4 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Wed, 16 Dec 2020 22:20:11 +0100 Subject: [PATCH 03/19] Start integrating default json serializer to data model --- src.compiler/CloneBuilder.ts | 20 +--- src.compiler/JsonSerializationBuilder.ts | 126 ++++++++++++++++------- src/model/Bar.ts | 5 + src/model/Beat.ts | 41 +++++--- src/model/Chord.ts | 2 + src/model/InstrumentArticulation.ts | 1 + src/model/MasterBar.ts | 5 + src/model/Note.ts | 20 ++-- src/model/PlaybackInformation.ts | 1 + src/model/RenderStylesheet.ts | 1 + src/model/Score.ts | 19 ++++ src/model/Staff.ts | 6 +- src/model/Track.ts | 3 + src/model/Voice.ts | 3 + 14 files changed, 172 insertions(+), 81 deletions(-) diff --git a/src.compiler/CloneBuilder.ts b/src.compiler/CloneBuilder.ts index fb23a8bb2..456a9f0bf 100644 --- a/src.compiler/CloneBuilder.ts +++ b/src.compiler/CloneBuilder.ts @@ -1,5 +1,6 @@ import * as ts from 'typescript'; import { getTypeWithNullableInfo } from './BuilderHelpers'; +import { unwrapArrayItemType } from './BuilderHelpers'; import { isPrimitiveType } from './BuilderHelpers'; function isClonable(type: ts.Type): boolean { @@ -15,23 +16,6 @@ function isClonable(type: ts.Type): boolean { return false; } -function unwrapArrayItemType(type: ts.Type, typeChecker: ts.TypeChecker): ts.Type | null { - if (type.symbol && type.symbol.name === 'Array') { - return (type as ts.TypeReference).typeArguments![0]; - } - - if (isPrimitiveType(type)) { - return null; - } - - if (type.isUnion()) { - const nonNullable = typeChecker.getNonNullableType(type); - return unwrapArrayItemType(nonNullable, typeChecker); - } - - return null; -} - function generateClonePropertyStatements(prop: ts.PropertyDeclaration, typeChecker: ts.TypeChecker, factory: ts.NodeFactory): ts.Statement[] { const propertyType = getTypeWithNullableInfo(typeChecker, prop.type); @@ -237,7 +221,7 @@ function isCloneMember(propertyDeclaration: ts.PropertyDeclaration) { return false; } - if (ts.getJSDocTags(propertyDeclaration).find(t => t.tagName.text === 'computed')) { + if (ts.getJSDocTags(propertyDeclaration).find(t => t.tagName.text === 'clone_ignore')) { return false; } diff --git a/src.compiler/JsonSerializationBuilder.ts b/src.compiler/JsonSerializationBuilder.ts index b688ef676..597fca785 100644 --- a/src.compiler/JsonSerializationBuilder.ts +++ b/src.compiler/JsonSerializationBuilder.ts @@ -5,6 +5,7 @@ import { isEnumType } from './BuilderHelpers'; import { wrapToNonNull } from './BuilderHelpers'; import { isTypedArray } from './BuilderHelpers'; import { isMap } from './BuilderHelpers'; +import { unwrapArrayItemType } from './BuilderHelpers'; ; interface JsonProperty { property: ts.PropertyDeclaration; @@ -21,8 +22,6 @@ function isImmutable(type: ts.Type): boolean { } function generateToJsonBodyForClass( - classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[], factory: ts.NodeFactory ): ts.Block { return factory.createBlock([ @@ -54,7 +53,6 @@ function generateToJsonBodyForClass( } function generateFillToJsonBodyForClass( program: ts.Program, - classDeclaration: ts.ClassDeclaration, propertiesToSerialize: JsonProperty[], factory: ts.NodeFactory ): ts.Block { @@ -76,33 +74,71 @@ function generateFillToJsonBodyForClass( }; if (jsonName) { - const type = getTypeWithNullableInfo(program.getTypeChecker(), prop.property.type); + const typeChecker = program.getTypeChecker(); + const type = getTypeWithNullableInfo(typeChecker, prop.property.type); if (isPrimitiveType(type.type)) { // json.jsonName = this.fieldName statements.push(assignToJsonName(accessField())); } else if (isTypedArray(type.type)) { - // json.jsonName = this.fieldName ? this.fieldName.slice() : null - if (type.isNullable) { - statements.push( - assignToJsonName( - factory.createConditionalExpression( - accessField(), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() + const arrayItemType = unwrapArrayItemType(type.type, typeChecker); + if (!arrayItemType || isPrimitiveType(arrayItemType)) { + // json.jsonName = this.fieldName ? this.fieldName.slice() : null + if (type.isNullable) { + statements.push( + assignToJsonName( + factory.createConditionalExpression( + accessField(), + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() + ) ) - ) - ); + ); + } else { + statements.push( + assignToJsonName(factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) + ); + } } else { - statements.push( - assignToJsonName(factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) - ); + // json.jsonName = this.fieldName ? this.fieldName.map($li => $li.toJson()) : null + const mapCall = factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'map'), undefined, [ + factory.createArrowFunction( + undefined, + undefined, + [factory.createParameterDeclaration(undefined, undefined, undefined, '$li')], + undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('$li'), + 'toJson' + ), + undefined, [] + ) + ), + ]); + if (type.isNullable) { + statements.push( + assignToJsonName( + factory.createConditionalExpression( + accessField(), + factory.createToken(ts.SyntaxKind.QuestionToken), + mapCall, + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() + ) + ) + ); + } else { + statements.push( + assignToJsonName(mapCall) + ); + } } } else if (isMap(type.type)) { const mapType = type.type as ts.TypeReference; - if (!isEnumType(mapType.typeArguments[0]) || !isPrimitiveType(mapType.typeArguments[1])) { - throw new Error('only Map maps are supported extend if needed!'); + if (!isPrimitiveType(mapType.typeArguments[0])) { + throw new Error('only Map maps are supported extend if needed!'); } // json.jsonName = { } as any; // this.fieldName.forEach((val, key) => (json.jsonName as any)[key] = val)) @@ -216,7 +252,6 @@ function generateFillToJsonBodyForClass( } function generateFromJsonBodyForClass( classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[], factory: ts.NodeFactory ): ts.Block { const statements: ts.Statement[] = []; @@ -263,8 +298,6 @@ function generateFromJsonBodyForClass( return factory.createBlock(statements); } function generateFillFromJsonBodyForClass( - classDeclaration: ts.ClassDeclaration, - propertiesToSerialize: JsonProperty[], factory: ts.NodeFactory ): ts.Block { return factory.createBlock([ @@ -347,7 +380,6 @@ function createEnumMapping(value: string, type: ts.Type, factory: ts.NodeFactory function generateSetPropertyMethodBodyForClass( program: ts.Program, - classDeclaration: ts.ClassDeclaration, propertiesToSerialize: JsonProperty[], factory: ts.NodeFactory ): ts.Block { @@ -416,8 +448,22 @@ function generateSetPropertyMethodBodyForClass( // return true; const mapType = type.type as ts.TypeReference; - if (!isEnumType(mapType.typeArguments[0]) || !isPrimitiveType(mapType.typeArguments[1])) { - throw new Error('only Map maps are supported extend if needed!'); + if (!isPrimitiveType(mapType.typeArguments[0])) { + throw new Error('only Map maps are supported extend if needed!'); + } + + const mapKey = isEnumType(mapType.typeArguments[0]) + ? createEnumMapping('$mk', mapType.typeArguments![0], factory) + : factory.createIdentifier('$mk'); + + let mapValue: ts.Expression = factory.createElementAccessExpression(factory.createIdentifier('value'), factory.createIdentifier('$mk')); + if (!isPrimitiveType(mapType.typeArguments[1])) { + mapValue = factory.createCallExpression( + // TypeName.fromJson + factory.createPropertyAccessExpression(factory.createIdentifier(mapType.typeArguments[1].symbol.name), 'fromJson'), + [], + [factory.createIdentifier('value')] + ); } caseStatements.push(assignField(factory.createNewExpression(factory.createIdentifier('Map'), undefined, []))); @@ -442,8 +488,8 @@ function generateSetPropertyMethodBodyForClass( ), undefined, [ - createEnumMapping('$mk', mapType.typeArguments![0], factory), - factory.createElementAccessExpression(factory.createIdentifier('value'), factory.createIdentifier('$mk')) + mapKey, + mapValue ] ) ) @@ -620,17 +666,19 @@ function rewriteClassForJsonSerialization( classDeclaration.members.forEach(member => { if (ts.isPropertyDeclaration(member)) { const propertyDeclaration = member as ts.PropertyDeclaration; - if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword)) { + if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind == ts.SyntaxKind.PrivateKeyword)) { const jsonNames = [member.name.getText(sourceFile)]; if (ts.getJSDocTags(member).find(t => t.tagName.text === 'json_on_parent')) { jsonNames.push(''); } - propertiesToSerialize.push({ - property: propertyDeclaration, - jsonNames: jsonNames - }); + if (!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_ignore')) { + propertiesToSerialize.push({ + property: propertyDeclaration, + jsonNames: jsonNames + }); + } } newMembers.push(member); } else if (ts.isMethodDeclaration(member)) { @@ -823,35 +871,35 @@ function rewriteClassForJsonSerialization( toJsonMethod = updateMethodBody( toJsonMethod, ['obj'], - generateToJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + generateToJsonBodyForClass(factory), factory ); fillToJsonMethod = updateMethodBody( fillToJsonMethod, ['json'], - generateFillToJsonBodyForClass(program, classDeclaration, propertiesToSerialize, factory), + generateFillToJsonBodyForClass(program, propertiesToSerialize, factory), factory ); fromJsonMethod = updateMethodBody( fromJsonMethod, ['json'], - generateFromJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + generateFromJsonBodyForClass(classDeclaration, factory), factory ); fillFromJsonMethod = updateMethodBody( fillFromJsonMethod, ['json'], - generateFillFromJsonBodyForClass(classDeclaration, propertiesToSerialize, factory), + generateFillFromJsonBodyForClass(factory), factory ); setPropertyMethod = updateMethodBody( setPropertyMethod, ['property', 'value'], - generateSetPropertyMethodBodyForClass(program, classDeclaration, propertiesToSerialize, factory), + generateSetPropertyMethodBodyForClass(program, propertiesToSerialize, factory), factory ); diff --git a/src/model/Bar.ts b/src/model/Bar.ts index df52f1a11..f72095e4b 100644 --- a/src/model/Bar.ts +++ b/src/model/Bar.ts @@ -8,6 +8,7 @@ import { Settings } from '@src/Settings'; /** * A bar is a single block within a track, also known as Measure. + * @json */ export class Bar { private static _globalBarId: number = 0; @@ -24,11 +25,13 @@ export class Bar { /** * Gets or sets the next bar that comes after this bar. + * @json_ignore */ public nextBar: Bar | null = null; /** * Gets or sets the previous bar that comes before this bar. + * @json_ignore */ public previousBar: Bar | null = null; @@ -44,11 +47,13 @@ export class Bar { /** * Gets or sets the reference to the parent staff. + * @json_ignore */ public staff!: Staff; /** * Gets or sets the list of voices contained in this bar. + * @json_add addVoice */ public voices: Voice[] = []; diff --git a/src/model/Beat.ts b/src/model/Beat.ts index f389abe16..29ad4b4f5 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -43,6 +43,7 @@ export enum BeatBeamingMode { /** * A beat is a single block within a bar. A beat is a combination * of several notes played at the same time. + * @json * @cloneable */ export class Beat { @@ -50,7 +51,7 @@ export class Beat { /** * Gets or sets the unique id of this beat. - * @computed + * @clone_ignore */ public id: number = Beat._globalBeatId++; @@ -61,13 +62,15 @@ export class Beat { /** * Gets or sets the previous beat within the whole song. - * @computed + * @json_ignore + * @clone_ignore */ public previousBeat: Beat | null = null; /** * Gets or sets the next beat within the whole song. - * @computed + * @json_ignore + * @clone_ignore */ public nextBeat: Beat | null = null; @@ -77,12 +80,14 @@ export class Beat { /** * Gets or sets the reference to the parent voice this beat belongs to. - * @computed + * @json_ignore + * @clone_ignore */ public voice!: Voice; /** * Gets or sets the list of notes contained in this beat. + * @json_add addNote * @clone_add addCloneNote */ public notes: Note[] = []; @@ -130,25 +135,29 @@ export class Beat { /** * Gets or sets the note with the lowest pitch in this beat. Only visible notes are considered. - * @computed + * @json_ignore + * @clone_ignore */ public minNote: Note | null = null; /** * Gets or sets the note with the highest pitch in this beat. Only visible notes are considered. - * @computed + * @json_ignore + * @clone_ignore */ public maxNote: Note | null = null; /** * Gets or sets the note with the highest string number in this beat. Only visible notes are considered. - * @computed + * @json_ignore + * @clone_ignore */ public maxStringNote: Note | null = null; /** * Gets or sets the note with the lowest string number in this beat. Only visible notes are considered. - * @computed + * @json_ignore + * @clone_ignore */ public minStringNote: Note | null = null; @@ -244,7 +253,8 @@ export class Beat { } /** - * @computed + * @clone_ignore + * @json_ignore */ public tupletGroup: TupletGroup | null = null; @@ -260,19 +270,22 @@ export class Beat { /** * Gets or sets the points defining the whammy bar usage. + * @json_add addWhammyBarPoint * @clone_add addWhammyBarPoint */ public whammyBarPoints: BendPoint[] = []; /** * Gets or sets the highest point with for the highest whammy bar value. - * @computed + * @json_ignore + * @clone_ignore */ public maxWhammyPoint: BendPoint | null = null; /** * Gets or sets the highest point with for the lowest whammy bar value. - * @computed + * @json_ignore + * @clone_ignore */ public minWhammyPoint: BendPoint | null = null; @@ -375,12 +388,14 @@ export class Beat { } /** - * @computed + * @clone_ignore + * @json_ignore */ public effectSlurOrigin: Beat | null = null; /** - * @computed + * @clone_ignore + * @json_ignore */ public effectSlurDestination: Beat | null = null; diff --git a/src/model/Chord.ts b/src/model/Chord.ts index 110434629..b7b24e6ad 100644 --- a/src/model/Chord.ts +++ b/src/model/Chord.ts @@ -2,6 +2,7 @@ import { Staff } from '@src/model/Staff'; /** * A chord definition. + * @json */ export class Chord { /** @@ -28,6 +29,7 @@ export class Chord { /** * Gets or sets the staff the chord belongs to. + * @json_ignore */ public staff!: Staff; diff --git a/src/model/InstrumentArticulation.ts b/src/model/InstrumentArticulation.ts index 18a4aea2b..fd50fbbfe 100644 --- a/src/model/InstrumentArticulation.ts +++ b/src/model/InstrumentArticulation.ts @@ -4,6 +4,7 @@ import { MusicFontSymbol } from "./MusicFontSymbol"; /** * Describes an instrument articulation which is used for percussions. + * @json */ export class InstrumentArticulation { /** diff --git a/src/model/MasterBar.ts b/src/model/MasterBar.ts index 5e40f4d46..0fd037e12 100644 --- a/src/model/MasterBar.ts +++ b/src/model/MasterBar.ts @@ -12,6 +12,7 @@ import { TripletFeel } from '@src/model/TripletFeel'; /** * The MasterBar stores information about a bar which affects * all tracks. + * @json */ export class MasterBar { public static readonly MaxAlternateEndings: number = 8; @@ -23,11 +24,13 @@ export class MasterBar { /** * Gets or sets the next masterbar in the song. + * @json_ignore */ public nextMasterBar: MasterBar | null = null; /** * Gets or sets the next masterbar in the song. + * @json_ignore */ public previousMasterBar: MasterBar | null = null; @@ -67,6 +70,7 @@ export class MasterBar { /** * Gets or sets the repeat group this bar belongs to. + * @json_ignore */ public repeatGroup!: RepeatGroup; @@ -106,6 +110,7 @@ export class MasterBar { /** * Gets or sets the reference to the score this song belongs to. + * @json_ignore */ public score!: Score; diff --git a/src/model/Note.ts b/src/model/Note.ts index 138df14d9..49b4bc5ec 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -31,7 +31,7 @@ export class Note { public static GlobalNoteId: number = 0; /** * Gets or sets the unique id of this note. - * @computed + * @clone_ignore */ public id: number = Note.GlobalNoteId++; @@ -57,7 +57,7 @@ export class Note { /** * Gets or sets the note from which this note continues the bend. - * @computed + * @clone_ignore */ public bendOrigin: Note | null = null; @@ -74,7 +74,7 @@ export class Note { /** * Gets or sets the bend point with the highest bend value. - * @computed + * @clone_ignore */ public maxBendPoint: BendPoint | null = null; @@ -336,7 +336,7 @@ export class Note { /** * Gets or sets the destination note for the let-ring effect. - * @computed + * @clone_ignore */ public letRingDestination: Note | null = null; @@ -347,7 +347,7 @@ export class Note { /** * Gets or sets the destination note for the palm-mute effect. - * @computed + * @clone_ignore */ public palmMuteDestination: Note | null = null; @@ -373,13 +373,13 @@ export class Note { /** * Gets or sets the target note for several slide types. - * @computed + * @clone_ignore */ public slideTarget: Note | null = null; /** * Gets or sets the source note for several slide types. - * @computed + * @clone_ignore */ public slideOrigin: Note | null = null; @@ -467,7 +467,7 @@ export class Note { /** * Gets or sets the reference to the parent beat to which this note belongs to. - * @computed + * @clone_ignore */ public beat!: Beat; @@ -485,12 +485,12 @@ export class Note { } /** - * @computed + * @clone_ignore */ public effectSlurOrigin: Note | null = null; /** - * @computed + * @clone_ignore */ public effectSlurDestination: Note | null = null; diff --git a/src/model/PlaybackInformation.ts b/src/model/PlaybackInformation.ts index 7c0d10474..696b09a55 100644 --- a/src/model/PlaybackInformation.ts +++ b/src/model/PlaybackInformation.ts @@ -1,6 +1,7 @@ /** * This public class stores the midi specific information of a track needed * for playback. + * @json */ export class PlaybackInformation { /** diff --git a/src/model/RenderStylesheet.ts b/src/model/RenderStylesheet.ts index 45bb431cd..445a56355 100644 --- a/src/model/RenderStylesheet.ts +++ b/src/model/RenderStylesheet.ts @@ -1,6 +1,7 @@ /** * This class represents the rendering stylesheet. * It contains settings which control the display of the score when rendered. + * @json */ export class RenderStylesheet { /** diff --git a/src/model/Score.ts b/src/model/Score.ts index 3d00ea573..f0249699b 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -9,6 +9,7 @@ import { Note } from './Note'; * The score is the root node of the complete * model. It stores the basic information of * a song and stores the sub components. + * @json */ export class Score { private _noteByIdLookup: Map = new Map(); @@ -76,11 +77,13 @@ export class Score { /** * Gets or sets a list of all masterbars contained in this song. + * @json_add addMasterBar */ public masterBars: MasterBar[] = []; /** * Gets or sets a list of all tracks contained in this song. + * @json_add addTrack */ public tracks: Track[] = []; @@ -143,4 +146,20 @@ export class Score { ? this._noteByIdLookup.get(noteId)! : null; } + + /** + * @target web + */ + public static fromJson(json: any): Score { + // dynamically implemented via AST transformer + return new Score(); + } + + /** + * @target web + */ + public static toJson(score: Score): unknown { + // dynamically implemented via AST transformer + return null; + } } diff --git a/src/model/Staff.ts b/src/model/Staff.ts index 55d6b2528..9e74af1bf 100644 --- a/src/model/Staff.ts +++ b/src/model/Staff.ts @@ -6,6 +6,7 @@ import { Settings } from '@src/Settings'; /** * This class describes a single staff within a track. There are instruments like pianos * where a single track can contain multiple staffs. + * @json */ export class Staff { /** @@ -15,21 +16,24 @@ export class Staff { /** * Gets or sets the reference to the track this staff belongs to. + * @json_ignore */ public track!: Track; /** * Gets or sets a list of all bars contained in this staff. + * @json_add addBar */ public bars: Bar[] = []; /** * Gets or sets a list of all chords defined for this staff. {@link Beat.chordId} refers to entries in this lookup. + * @json_add addChord */ public chords: Map = new Map(); /** - * Gets or sets the fret on which a capo is set. s + * Gets or sets the fret on which a capo is set. */ public capo: number = 0; diff --git a/src/model/Track.ts b/src/model/Track.ts index e2efb1915..f29c368c6 100644 --- a/src/model/Track.ts +++ b/src/model/Track.ts @@ -10,6 +10,7 @@ import { InstrumentArticulation } from './InstrumentArticulation'; /** * This public class describes a single track or instrument of score. * It is bascially a list of staffs containing individual music notation kinds. + * @json */ export class Track { private static readonly ShortNameMaxLength: number = 10; @@ -20,11 +21,13 @@ export class Track { /** * Gets or sets the reference this track belongs to. + * @json_ignore */ public score!: Score; /** * Gets or sets the list of staffs that are defined for this track. + * @json_add addStaff */ public staves: Staff[] = []; diff --git a/src/model/Voice.ts b/src/model/Voice.ts index 8f903da81..67c8e8fba 100644 --- a/src/model/Voice.ts +++ b/src/model/Voice.ts @@ -8,6 +8,7 @@ import { Settings } from '@src/Settings'; /** * A voice represents a group of beats * that can be played during a bar. + * @json */ export class Voice { private _beatLookup!: Map; @@ -19,11 +20,13 @@ export class Voice { /** * Gets or sets the reference to the bar this voice belongs to. + * @json_ignore */ public bar!: Bar; /** * Gets or sets the list of beats contained in this voice. + * @json_add addBeat */ public beats: Beat[] = []; From 52a5f8bf04f4d8755024fa939b9d7ac17047e2e7 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Wed, 16 Dec 2020 22:51:52 +0100 Subject: [PATCH 04/19] Untested serializer --- src.compiler/BuilderHelpers.ts | 17 +++ src.compiler/CloneBuilder.ts | 1 - src.compiler/JsonSerializationBuilder.ts | 143 ++++++++++++++++++----- src/model/JsonConverter.ts | 10 +- 4 files changed, 137 insertions(+), 34 deletions(-) diff --git a/src.compiler/BuilderHelpers.ts b/src.compiler/BuilderHelpers.ts index 04d225a26..b5347bf06 100644 --- a/src.compiler/BuilderHelpers.ts +++ b/src.compiler/BuilderHelpers.ts @@ -25,6 +25,23 @@ export function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNo }; } +export function unwrapArrayItemType(type: ts.Type, typeChecker: ts.TypeChecker): ts.Type | null { + if (type.symbol && type.symbol.name === 'Array') { + return (type as ts.TypeReference).typeArguments![0]; + } + + if (isPrimitiveType(type)) { + return null; + } + + if (type.isUnion()) { + const nonNullable = typeChecker.getNonNullableType(type); + return unwrapArrayItemType(nonNullable, typeChecker); + } + + return null; +} + export function isPrimitiveType(type: ts.Type) { if (hasFlag(type, ts.TypeFlags.Number)) { diff --git a/src.compiler/CloneBuilder.ts b/src.compiler/CloneBuilder.ts index 456a9f0bf..3fc216b8f 100644 --- a/src.compiler/CloneBuilder.ts +++ b/src.compiler/CloneBuilder.ts @@ -1,7 +1,6 @@ import * as ts from 'typescript'; import { getTypeWithNullableInfo } from './BuilderHelpers'; import { unwrapArrayItemType } from './BuilderHelpers'; -import { isPrimitiveType } from './BuilderHelpers'; function isClonable(type: ts.Type): boolean { if (!type.symbol) { diff --git a/src.compiler/JsonSerializationBuilder.ts b/src.compiler/JsonSerializationBuilder.ts index 597fca785..71fd00e49 100644 --- a/src.compiler/JsonSerializationBuilder.ts +++ b/src.compiler/JsonSerializationBuilder.ts @@ -1,3 +1,4 @@ +import { slice } from 'lodash'; import * as ts from 'typescript'; import { getTypeWithNullableInfo } from './BuilderHelpers'; import { isPrimitiveType } from './BuilderHelpers'; @@ -150,6 +151,17 @@ function generateFillToJsonBodyForClass( ) ) ); + const mapValue = isPrimitiveType(mapType.typeArguments[1]) + ? factory.createIdentifier('$mv') + : factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('$mv'), + 'toJson' + ), + undefined, + [] + ); + statements.push( factory.createExpressionStatement( factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'forEach'), undefined, [ @@ -172,7 +184,7 @@ function generateFillToJsonBodyForClass( ), factory.createIdentifier('$mk') ), - factory.createIdentifier('$mv') + mapValue ) ) ]) @@ -413,38 +425,109 @@ function generateSetPropertyMethodBodyForClass( caseStatements.push(assignField(factory.createIdentifier('value'))); caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isTypedArray(type.type)) { - // nullable: - // this.fieldName = value ? value.slice() : null - // return true; - - // not nullable: - // this.fieldName = value.slice() - // return true; + const arrayItemType = unwrapArrayItemType(type.type, typeChecker); + if (!arrayItemType || isPrimitiveType(arrayItemType)) { + // nullable: + // this.fieldName = value ? value.slice() : null + // return true; - if (type.isNullable) { - caseStatements.push( - assignField( - factory.createConditionalExpression( - factory.createIdentifier('value'), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], []), - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() + // not nullable: + // this.fieldName = value.slice() + // return true; + const sliceCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], []); + if (type.isNullable) { + caseStatements.push( + assignField( + factory.createConditionalExpression( + factory.createIdentifier('value'), + factory.createToken(ts.SyntaxKind.QuestionToken), + sliceCall, + factory.createToken(ts.SyntaxKind.ColonToken), + factory.createNull() + ) ) - ) - ); + ); + } else { + caseStatements.push( + assignField(sliceCall) + ); + } + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else { - caseStatements.push( - assignField(factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], [])) - ); + const collectionAddMethod = ts.getJSDocTags(prop.property) + .filter(t => t.tagName.text === 'json_add') + .map(t => t.comment ?? "")[0]; + + // this.fieldName = []; + // for(const $li of value) { + // this.addFieldName(Type.FromJson($li)); + // } + // or + // for(const $li of value) { + // this.fieldName.push(Type.FromJson($li)); + // } + const loopItems = [ + assignField(factory.createArrayLiteralExpression(undefined)), + factory.createForOfStatement( + undefined, + factory.createVariableDeclarationList( + [factory.createVariableDeclaration('$li')], + ts.NodeFlags.Const + ), + factory.createIdentifier('value'), + factory.createExpressionStatement( + collectionAddMethod + // this.addFieldName(TypeName.FromJson($li)) + ? factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + collectionAddMethod + ), + undefined, + [factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'fromJson'), + [], + [factory.createIdentifier('$li')] + )] + ) + // this.fieldName.push(TypeName.FromJson($li)) + : factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression( + factory.createThis(), + fieldName + ), + 'push' + ), + undefined, + [factory.createCallExpression( + factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'fromJson'), + [], + [factory.createIdentifier('$li')] + )] + ) + ) + )]; + + if (type.isNullable) { + caseStatements.push(factory.createIfStatement( + factory.createIdentifier('value'), + factory.createBlock(loopItems) + )); + } else { + caseStatements.push(...loopItems); + } } - caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isMap(type.type)) { // this.fieldName = new Map(); // for(let key in value) { // if(value.hasOwnProperty(key) this.fieldName.set(, value[key]); // } + // or + // for(let key in value) { + // if(value.hasOwnProperty(key) this.addFieldName(, value[key]); + // } // return true; const mapType = type.type as ts.TypeReference; @@ -466,6 +549,10 @@ function generateSetPropertyMethodBodyForClass( ); } + const collectionAddMethod = ts.getJSDocTags(prop.property) + .filter(t => t.tagName.text === 'json_add') + .map(t => t.comment ?? "")[0]; + caseStatements.push(assignField(factory.createNewExpression(factory.createIdentifier('Map'), undefined, []))); caseStatements.push( factory.createForInStatement( @@ -482,10 +569,12 @@ function generateSetPropertyMethodBodyForClass( ), factory.createExpressionStatement( factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)), - factory.createIdentifier('set') - ), + collectionAddMethod + ? factory.createPropertyAccessExpression(factory.createThis(), collectionAddMethod) + : factory.createPropertyAccessExpression( + factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)), + factory.createIdentifier('set') + ), undefined, [ mapKey, diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 8668cba9d..c3629ce5a 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -35,8 +35,7 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - // TODO: new json serializer - return score; + return Score.toJson(score); } /** @@ -56,10 +55,9 @@ export class JsonConverter { * @returns The converted score object. */ public static jsObjectToScore(jsObject: any, settings?: Settings): Score { - let score2: Score = new Score(); - - score2.finish(settings ?? new Settings()); - return score2; + let score: Score = Score.fromJson(jsObject); + score.finish(settings ?? new Settings()); + return score; } public static jsObjectToMidiFile(midi: any): MidiFile { From 3f340f2621484f0fc966d55c0d67af025886ede1 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 17 Dec 2020 01:03:57 +0100 Subject: [PATCH 05/19] Activated JSON serialization for model and JS tests --- karma.conf.js | 20 +++ src.compiler/AlphaTabTransformations.ts | 27 ++++ src.compiler/CloneBuilder.ts | 22 +--- src.compiler/JsonSerializationBuilder.ts | 81 +++++++----- src.csharp/AlphaTab.Test/TestPlatform.cs | 5 + src/model/Automation.ts | 1 + src/model/Bar.ts | 4 + src/model/Beat.ts | 25 ++-- src/model/BendPoint.ts | 1 + src/model/Fermata.ts | 1 + src/model/MasterBar.ts | 4 + src/model/Note.ts | 6 + src/model/Score.ts | 6 + src/model/Staff.ts | 7 +- src/model/Track.ts | 4 + src/model/Voice.ts | 4 + test/TestPlatform.ts | 21 +++ test/model/JsonConverter.test.ts | 156 +++++++++++++++++++++++ tsconfig.base.json | 7 +- 19 files changed, 327 insertions(+), 75 deletions(-) create mode 100644 src.compiler/AlphaTabTransformations.ts create mode 100644 test/model/JsonConverter.test.ts diff --git a/karma.conf.js b/karma.conf.js index f7b7d5e0e..19595f6e8 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -15,6 +15,7 @@ const storage = multer.diskStorage({ const upload = multer({ storage: storage }); const cors = require('cors'); const fs = require('fs'); +const path = require('path'); module.exports = function (config) { config.set({ @@ -54,6 +55,25 @@ module.exports = function (config) { port: 8090, appVisitor: function (app, log) { app.use(cors()); + app.get( + '/list-files', + function (req, res) { + log.info(`loading files from ${req.query.dir}`); + + const directoryPath = path.join(__dirname, req.query.dir); + fs.readdir(directoryPath, (err, files) => { + //handling error + if (err) { + res.status(400); + res.send(JSON.stringify(`Error: ${err.message}`)); + } else { + res.send(JSON.stringify(files.filter(f => + fs.statSync(path.join(directoryPath, f)).isFile() + ))); + } + }); + } + ); app.post( '/save-visual-error', upload.fields([ diff --git a/src.compiler/AlphaTabTransformations.ts b/src.compiler/AlphaTabTransformations.ts new file mode 100644 index 000000000..ad8db2bb4 --- /dev/null +++ b/src.compiler/AlphaTabTransformations.ts @@ -0,0 +1,27 @@ +import * as ts from 'typescript'; +import { rewriteClassForCloneable } from './CloneBuilder' +import { rewriteClassForJsonSerialization } from './JsonSerializationBuilder' + +export default function (program: ts.Program) { + return (ctx: ts.TransformationContext) => { + return (sourceFile: ts.SourceFile) => { + function visitor(node: ts.Node): ts.Node { + if (ts.isClassDeclaration(node)) { + const isClonable = ts.getJSDocTags(node).find(t => t.tagName.text === 'cloneable'); + const isJson = ts.getJSDocTags(node).find(t => t.tagName.text === 'json'); + if (isClonable) { + node = rewriteClassForCloneable(node, ctx.factory, program.getTypeChecker()); + } + + if (isJson) { + node = rewriteClassForJsonSerialization(program, node as ts.ClassDeclaration, sourceFile, ctx.factory); + } + } + + return node; + } + + return ts.visitEachChild(sourceFile, visitor, ctx); + }; + }; +} diff --git a/src.compiler/CloneBuilder.ts b/src.compiler/CloneBuilder.ts index 3fc216b8f..244caf05f 100644 --- a/src.compiler/CloneBuilder.ts +++ b/src.compiler/CloneBuilder.ts @@ -227,7 +227,7 @@ function isCloneMember(propertyDeclaration: ts.PropertyDeclaration) { return true; } -function rewriteClassForCloneable( +export function rewriteClassForCloneable( classDeclaration: ts.ClassDeclaration, factory: ts.NodeFactory, typeChecker: ts.TypeChecker @@ -302,22 +302,4 @@ function rewriteClassForCloneable( classDeclaration.heritageClauses, newMembers ); -} - -export default function (program: ts.Program) { - return (ctx: ts.TransformationContext) => { - return (sourceFile: ts.SourceFile) => { - function visitor(node: ts.Node): ts.Node { - if (ts.isClassDeclaration(node)) { - if (ts.getJSDocTags(node).find(t => t.tagName.text === 'cloneable')) { - return rewriteClassForCloneable(node, ctx.factory, program.getTypeChecker()); - } - } - - return node; - } - - return ts.visitEachChild(sourceFile, visitor, ctx); - }; - }; -} +} \ No newline at end of file diff --git a/src.compiler/JsonSerializationBuilder.ts b/src.compiler/JsonSerializationBuilder.ts index 71fd00e49..0475dcc23 100644 --- a/src.compiler/JsonSerializationBuilder.ts +++ b/src.compiler/JsonSerializationBuilder.ts @@ -102,7 +102,12 @@ function generateFillToJsonBodyForClass( ); } } else { - // json.jsonName = this.fieldName ? this.fieldName.map($li => $li.toJson()) : null + // avoid the type being elided + factory.createNotEmittedStatement(factory.createExpressionStatement( + factory.createIdentifier(arrayItemType.symbol.name) + )); + + // json.jsonName = this.fieldName ? this.fieldName.map($li => TypeName.toJson($li)) : null const mapCall = factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'map'), undefined, [ factory.createArrowFunction( undefined, @@ -110,11 +115,9 @@ function generateFillToJsonBodyForClass( [factory.createParameterDeclaration(undefined, undefined, undefined, '$li')], undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('$li'), - 'toJson' - ), - undefined, [] + factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'toJson'), + undefined, + [factory.createIdentifier('$li')] ) ), ]); @@ -151,15 +154,21 @@ function generateFillToJsonBodyForClass( ) ) ); + + // avoid the type being elided + + if (!isPrimitiveType(mapType.typeArguments[1])) { + factory.createNotEmittedStatement(factory.createExpressionStatement( + factory.createIdentifier(mapType.typeArguments[1].symbol.name) + )); + } + const mapValue = isPrimitiveType(mapType.typeArguments[1]) ? factory.createIdentifier('$mv') : factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('$mv'), - 'toJson' - ), + factory.createPropertyAccessExpression(factory.createIdentifier(mapType.typeArguments[1].symbol.name), 'toJson'), undefined, - [] + [factory.createIdentifier('$mv')] ); statements.push( @@ -417,7 +426,23 @@ function generateSetPropertyMethodBodyForClass( if (isEnumType(type.type)) { // this.fieldName = enummapping // return true; - caseStatements.push(assignField(createEnumMapping('value', type.type, factory))); + if (type.isNullable) { + caseStatements.push(assignField( + factory.createConditionalExpression( + factory.createBinaryExpression( + factory.createIdentifier('value'), + ts.SyntaxKind.EqualsEqualsEqualsToken, + factory.createNull() + ), + factory.createToken(ts.SyntaxKind.QuestionToken), + factory.createNull(), + factory.createToken(ts.SyntaxKind.ColonToken), + createEnumMapping('value', type.type, factory) + ) + )); + } else { + caseStatements.push(assignField(createEnumMapping('value', type.type, factory))); + } caseStatements.push(factory.createReturnStatement(factory.createTrue())); } else if (isPrimitiveType(type.type)) { // this.fieldName = value @@ -517,6 +542,7 @@ function generateSetPropertyMethodBodyForClass( } else { caseStatements.push(...loopItems); } + caseStatements.push(factory.createReturnStatement(factory.createTrue())); } } else if (isMap(type.type)) { @@ -545,7 +571,7 @@ function generateSetPropertyMethodBodyForClass( // TypeName.fromJson factory.createPropertyAccessExpression(factory.createIdentifier(mapType.typeArguments[1].symbol.name), 'fromJson'), [], - [factory.createIdentifier('value')] + [mapValue] ); } @@ -734,7 +760,7 @@ function generateSetPropertyMethodBodyForClass( return factory.createBlock(statements); } -function rewriteClassForJsonSerialization( +export function rewriteClassForJsonSerialization( program: ts.Program, classDeclaration: ts.ClassDeclaration, sourceFile: ts.SourceFile, @@ -755,7 +781,10 @@ function rewriteClassForJsonSerialization( classDeclaration.members.forEach(member => { if (ts.isPropertyDeclaration(member)) { const propertyDeclaration = member as ts.PropertyDeclaration; - if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind == ts.SyntaxKind.PrivateKeyword)) { + if (!propertyDeclaration.modifiers.find(m => + m.kind === ts.SyntaxKind.StaticKeyword || + m.kind === ts.SyntaxKind.PrivateKeyword || + m.kind === ts.SyntaxKind.ReadonlyKeyword)) { const jsonNames = [member.name.getText(sourceFile)]; if (ts.getJSDocTags(member).find(t => t.tagName.text === 'json_on_parent')) { @@ -957,6 +986,8 @@ function rewriteClassForJsonSerialization( ); } + // let requiredTypes:ts.Identifier = []; + toJsonMethod = updateMethodBody( toJsonMethod, ['obj'], @@ -1009,22 +1040,4 @@ function rewriteClassForJsonSerialization( classDeclaration.heritageClauses, newMembers ); -} - -export default function (program: ts.Program) { - return (ctx: ts.TransformationContext) => { - return (sourceFile: ts.SourceFile) => { - function visitor(node: ts.Node): ts.Node { - if (ts.isClassDeclaration(node)) { - if (ts.getJSDocTags(node).find(t => t.tagName.text === 'json')) { - return rewriteClassForJsonSerialization(program, node, sourceFile, ctx.factory); - } - } - - return node; - } - - return ts.visitEachChild(sourceFile, visitor, ctx); - }; - }; -} +} \ No newline at end of file diff --git a/src.csharp/AlphaTab.Test/TestPlatform.cs b/src.csharp/AlphaTab.Test/TestPlatform.cs index 21ba9308a..fe843787d 100644 --- a/src.csharp/AlphaTab.Test/TestPlatform.cs +++ b/src.csharp/AlphaTab.Test/TestPlatform.cs @@ -13,5 +13,10 @@ public static async Task LoadFile(string path) await fs.CopyToAsync(ms); return new Uint8Array(ms.ToArray()); } + + public static Task> ListDirectory(string path) + { + return Task.FromResult((IList)Directory.EnumerateFiles(path).ToList()); + } } } diff --git a/src/model/Automation.ts b/src/model/Automation.ts index 6aafccdb4..4fa9a336d 100644 --- a/src/model/Automation.ts +++ b/src/model/Automation.ts @@ -23,6 +23,7 @@ export enum AutomationType { /** * Automations are used to change the behaviour of a song. * @cloneable + * @json */ export class Automation { /** diff --git a/src/model/Bar.ts b/src/model/Bar.ts index f72095e4b..ae0ab2b66 100644 --- a/src/model/Bar.ts +++ b/src/model/Bar.ts @@ -6,6 +6,10 @@ import { Staff } from '@src/model/Staff'; import { Voice } from '@src/model/Voice'; import { Settings } from '@src/Settings'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +Voice; + /** * A bar is a single block within a track, also known as Measure. * @json diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 29ad4b4f5..1bbd1507d 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -22,6 +22,13 @@ import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { BeamDirection } from '@src/rendering/utils/BeamDirection'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +Note; +Automation; +BendPoint; +Fermata; + /** * Lists the different modes on how beaming for a beat should be done. */ @@ -88,7 +95,7 @@ export class Beat { /** * Gets or sets the list of notes contained in this beat. * @json_add addNote - * @clone_add addCloneNote + * @clone_add addNote */ public notes: Note[] = []; @@ -448,25 +455,12 @@ export class Beat { } public addNote(note: Note): void { - this.addNoteInternal(note, -1); - } - - // @ts-ignore - private addCloneNote(clone:Note, original:Note) { - this.addNoteInternal(clone, original.realValue); - } - - private addNoteInternal(note: Note, realValue: number = -1): void { note.beat = this; note.index = this.notes.length; this.notes.push(note); if (note.isStringed) { this.noteStringLookup.set(note.string, note); } - if (realValue === -1) { - realValue = note.realValue; - } - this.noteValueLookup.set(realValue, note); } public removeNote(note: Note): void { @@ -797,8 +791,9 @@ export class Beat { return new Beat(); } - public chain() { + public chain() { for(const n of this.notes) { + this.noteValueLookup.set(n.realValue, n); n.chain(); } } diff --git a/src/model/BendPoint.ts b/src/model/BendPoint.ts index d39d153b5..9d08cf1c9 100644 --- a/src/model/BendPoint.ts +++ b/src/model/BendPoint.ts @@ -2,6 +2,7 @@ * A single point of a bending graph. Used to * describe WhammyBar and String Bending effects. * @cloneable + * @json */ export class BendPoint { public static readonly MaxPosition: number = 60; diff --git a/src/model/Fermata.ts b/src/model/Fermata.ts index fb1c98916..8c47b3d64 100644 --- a/src/model/Fermata.ts +++ b/src/model/Fermata.ts @@ -18,6 +18,7 @@ export enum FermataType { /** * Represents a fermata. + * @json */ export class Fermata { /** diff --git a/src/model/MasterBar.ts b/src/model/MasterBar.ts index 0fd037e12..6ad4cef86 100644 --- a/src/model/MasterBar.ts +++ b/src/model/MasterBar.ts @@ -9,6 +9,10 @@ import { Score } from '@src/model/Score'; import { Section } from '@src/model/Section'; import { TripletFeel } from '@src/model/TripletFeel'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +Fermata; + /** * The MasterBar stores information about a bar which affects * all tracks. diff --git a/src/model/Note.ts b/src/model/Note.ts index 49b4bc5ec..40dfdcc05 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -21,11 +21,16 @@ import { ModelUtils } from '@src/model/ModelUtils'; import { PickStroke } from './PickStroke'; import { PercussionMapper } from '@src/model/PercussionMapper'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +BendPoint; + /** * A note is a single played sound on a fretted instrument. * It consists of a fret offset and a string on which the note is played on. * It also can be modified by a lot of different effects. * @cloneable + * @json */ export class Note { public static GlobalNoteId: number = 0; @@ -468,6 +473,7 @@ export class Note { /** * Gets or sets the reference to the parent beat to which this note belongs to. * @clone_ignore + * @json_ignore */ public beat!: Beat; diff --git a/src/model/Score.ts b/src/model/Score.ts index f0249699b..91567200c 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -5,6 +5,12 @@ import { Track } from '@src/model/Track'; import { Settings } from '@src/Settings'; import { Note } from './Note'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +MasterBar; +RenderStylesheet; +Track; + /** * The score is the root node of the complete * model. It stores the basic information of diff --git a/src/model/Staff.ts b/src/model/Staff.ts index 9e74af1bf..a1a3ec511 100644 --- a/src/model/Staff.ts +++ b/src/model/Staff.ts @@ -3,6 +3,11 @@ import { Chord } from '@src/model/Chord'; import { Track } from '@src/model/Track'; import { Settings } from '@src/Settings'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +Bar; +Chord; + /** * This class describes a single staff within a track. There are instruments like pianos * where a single track can contain multiple staffs. @@ -30,7 +35,7 @@ export class Staff { * Gets or sets a list of all chords defined for this staff. {@link Beat.chordId} refers to entries in this lookup. * @json_add addChord */ - public chords: Map = new Map(); + public chords: Map = new Map(); /** * Gets or sets the fret on which a capo is set. diff --git a/src/model/Track.ts b/src/model/Track.ts index f29c368c6..02cecb00e 100644 --- a/src/model/Track.ts +++ b/src/model/Track.ts @@ -7,6 +7,10 @@ import { Staff } from '@src/model/Staff'; import { Settings } from '@src/Settings'; import { InstrumentArticulation } from './InstrumentArticulation'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +InstrumentArticulation; + /** * This public class describes a single track or instrument of score. * It is bascially a list of staffs containing individual music notation kinds. diff --git a/src/model/Voice.ts b/src/model/Voice.ts index 67c8e8fba..9fb32f283 100644 --- a/src/model/Voice.ts +++ b/src/model/Voice.ts @@ -5,6 +5,10 @@ import { Duration } from '@src/model/Duration'; import { GraceType } from '@src/model/GraceType'; import { Settings } from '@src/Settings'; +// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression +// the AST transformer reference is not respected so we add one manually +Beat; + /** * A voice represents a group of beats * that can be played during a bar. diff --git a/test/TestPlatform.ts b/test/TestPlatform.ts index 6fa8098de..92de3964f 100644 --- a/test/TestPlatform.ts +++ b/test/TestPlatform.ts @@ -34,6 +34,27 @@ export class TestPlatform { }); } + /** + * @target web + */ + public static listDirectory(path: string): Promise { + return new Promise((resolve, reject) => { + let x: XMLHttpRequest = new XMLHttpRequest(); + x.open('GET', 'http://localhost:8090/list-files?dir=' + path, true, null, null); + x.responseType = 'text'; + x.onreadystatechange = () => { + if (x.readyState === XMLHttpRequest.DONE) { + if (x.status === 200) { + resolve(JSON.parse(x.responseText)); + } else { + reject('Could not find path: ' + path + ', received:' + x.responseText); + } + } + }; + x.send(); + }); + } + public static async loadFileAsString(path: string): Promise { const data = await TestPlatform.loadFile(path); return IOHelper.toString(data, 'UTF-8'); diff --git a/test/model/JsonConverter.test.ts b/test/model/JsonConverter.test.ts new file mode 100644 index 000000000..e773eb53f --- /dev/null +++ b/test/model/JsonConverter.test.ts @@ -0,0 +1,156 @@ +import { ScoreLoader } from "@src/importer/ScoreLoader"; +import { JsonConverter } from "@src/model/JsonConverter"; +import { Score } from "@src/model/Score"; +import { TestPlatform } from "@test/TestPlatform"; + +describe('JsonConverterTest', () => { + const loadScore: (name: string) => Promise = async (name: string): Promise => { + const data = await TestPlatform.loadFile('test-data/' + name); + try { + return ScoreLoader.loadScoreFromBytes(data); + } + catch (e) { + return null; + } + }; + + function expectJsonEqual(expected: any, actual: any, path: string) { + const expectedType = typeof expected; + const actualType = typeof actual; + + // NOTE: performance wise expect() seems quite expensive + // that's why we do a manual check for most asserts + + if (actualType != expectedType) { + fail(`Type Mismatch on hierarchy: ${path}, '${actualType}' != '${expectedType}'`); + } + + switch (actualType) { + case 'boolean': + if ((actual as boolean) != (expected as boolean)) { + fail(`Boolean mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } + break; + case 'number': + if (Math.abs((actual as number) - (expected as number)) >= 0.000001) { + fail(`Number mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } + break; + case 'object': + if ((actual === null) !== (expected === null)) { + fail(`Null mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } else if (actual) { + if (Array.isArray(actual) !== Array.isArray(expected)) { + fail(`IsArray mismatch on hierarchy: ${path}`); + } else if (Array.isArray(actual) && Array.isArray(expected)) { + if (actual.length !== expected.length) { + fail(`Array Length mismatch on hierarchy: ${path}, ${actual.length} != ${expected.length}`); + } else { + for (let i = 0; i < actual.length; i++) { + expectJsonEqual(expected[i], actual[i], `${path}[${i}]`); + } + } + } else { + + const expectedKeys = Object.keys(expected); + const actualKeys = Object.keys(actual); + expectedKeys.sort(); + actualKeys.sort(); + + const actualKeyList = actualKeys.join(','); + const expectedKeyList = expectedKeys.join(','); + if (actualKeyList !== expectedKeyList) { + fail(`Object Keys mismatch on hierarchy: ${path}, '${actualKeyList}' != '${expectedKeyList}'`); + } else { + for (const key of actualKeys) { + switch (key) { + // some ignored keys + case 'id': + case 'hammerPullOriginId': + case 'hammerPullDestinationId': + case 'tieOriginId': + case 'tieDestinationId': + break; + default: + expectJsonEqual(expected[key], actual[key], `${path}.${key}`); + break; + } + } + + } + } + } + break; + case 'string': + if ((actual as string) != (expected as string)) { + fail(`String mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } + break; + case 'undefined': + if (actual !== expected) { + fail(`null mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } + break; + } + } + + const testRoundTripEqual: (name: string) => Promise = async (name: string): Promise => { + try { + const expected = await loadScore(name); + if (!expected) { + return; + } + + const expectedJson = JsonConverter.scoreToJsObject(expected); + const actual = JsonConverter.jsObjectToScore(expectedJson); + const actualJson = JsonConverter.scoreToJsObject(actual); + + expectJsonEqual(expectedJson, actualJson, '<' + name.substr(name.lastIndexOf('/') + 1) + '>'); + } catch (e) { + fail(e); + } + }; + + const testRoundTripFolderEqual: (name: string) => Promise = async (name: string): Promise => { + const files: string[] = await TestPlatform.listDirectory(`test-data/${name}`); + for (const file of files) { + await testRoundTripEqual(`${name}/${file}`); + } + }; + + it('importer', async () => { + await testRoundTripFolderEqual('guitarpro7'); + }); + + it('visual-effects-and-annotations', async () => { + await testRoundTripFolderEqual('visual-tests/effects-and-annotations'); + }); + + it('visual-general', async () => { + await testRoundTripFolderEqual('visual-tests/general'); + }); + + it('visual-guitar-tabs', async () => { + await testRoundTripFolderEqual('visual-tests/guitar-tabs'); + }); + + it('visual-layout', async () => { + await testRoundTripFolderEqual('visual-tests/layout'); + }); + + it('visual-music-notation', async () => { + await testRoundTripFolderEqual('visual-tests/music-notation'); + }); + + it('visual-notation-legend', async () => { + await testRoundTripFolderEqual('visual-tests/notation-legend'); + }); + + it('visual-special-notes', async () => { + await testRoundTripFolderEqual('visual-tests/special-notes'); + }); + + it('visual-special-tracks', async () => { + await testRoundTripFolderEqual('visual-tests/special-tracks'); + }); +}); diff --git a/tsconfig.base.json b/tsconfig.base.json index fa4c85d68..4c5c1c7c1 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -35,11 +35,8 @@ ], "plugins": [ { - "transform": "./src.compiler/JsonSerializationBuilder.ts" - }, - { - "transform": "./src.compiler/CloneBuilder.ts" - }, + "transform": "./src.compiler/AlphaTabTransformations.ts" + } ] }, "include": [ From a36877a024374724952ef61f9432ff341c2a1126 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 17 Dec 2020 13:48:11 +0100 Subject: [PATCH 06/19] Generate TS files instead of in-memory code --- .vscode/launch.json | 24 + .vscode/settings.json | 3 +- package-lock.json | 103 +- package.json | 23 +- src.compiler/AlphaTabTransformations.ts | 27 - src.compiler/BuilderHelpers.ts | 39 +- src.compiler/CloneBuilder.ts | 305 ----- src.compiler/JsonSerializationBuilder.ts | 1043 --------------- src.compiler/TranspilerBase.ts | 40 + src.compiler/csharp/CSharpAstTransformer.ts | 11 +- src.compiler/csharp/CSharpEmitter.ts | 4 +- src.compiler/csharp/CSharpEmitterContext.ts | 6 +- src.compiler/csharp/CSharpTranspiler.ts | 87 +- src.compiler/typescript/AlphaTabGenerator.ts | 9 + src.compiler/typescript/CloneEmitter.ts | 362 +++++ src.compiler/typescript/EmitterBase.ts | 101 ++ src.compiler/typescript/SerializerEmitter.ts | 1174 +++++++++++++++++ src/Settings.ts | 34 +- src/generated/CoreSettingsSerializer.ts | 81 ++ src/generated/DisplaySettingsSerializer.ts | 100 ++ src/generated/ImporterSettingsSerializer.ts | 44 + src/generated/NotationSettingsSerializer.ts | 88 ++ src/generated/PlayerSettingsSerializer.ts | 85 ++ src/generated/RenderingResourcesSerializer.ts | 106 ++ src/generated/SettingsSerializer.ts | 35 + .../SlidePlaybackSettingsSerializer.ts | 48 + .../VibratoPlaybackSettingsSerializer.ts | 68 + src/generated/model/AutomationCloner.ts | 18 + src/generated/model/AutomationSerializer.ts | 57 + src/generated/model/BarSerializer.ts | 66 + src/generated/model/BeatCloner.ts | 65 + src/generated/model/BeatSerializer.ts | 221 ++++ src/generated/model/BendPointCloner.ts | 15 + src/generated/model/BendPointSerializer.ts | 44 + src/generated/model/ChordSerializer.ts | 64 + src/generated/model/FermataSerializer.ts | 45 + .../model/InstrumentArticulationSerializer.ts | 66 + src/generated/model/MasterBarSerializer.ts | 157 +++ src/generated/model/NoteCloner.ts | 59 + src/generated/model/NoteSerializer.ts | 222 ++++ .../model/PlaybackInformationSerializer.ts | 68 + .../model/RenderStylesheetSerializer.ts | 40 + src/generated/model/ScoreSerializer.ts | 124 ++ src/generated/model/SectionSerializer.ts | 44 + src/generated/model/StaffSerializer.ts | 93 ++ src/generated/model/TrackSerializer.ts | 93 ++ src/generated/model/VoiceSerializer.ts | 51 + src/importer/AlphaTexImporter.ts | 3 +- src/importer/GpifParser.ts | 6 +- src/model/Beat.ts | 10 +- src/model/JsonConverter.ts | 5 +- src/model/Note.ts | 13 +- src/model/Score.ts | 16 - src/model/Section.ts | 1 + src/platform/javascript/AlphaTabWebWorker.ts | 5 +- .../javascript/AlphaTabWorkerScoreRenderer.ts | 3 +- src/platform/javascript/BrowserUiFacade.ts | 3 +- tsconfig.base.json | 9 +- tsconfig.build-csharp.json | 2 +- tsconfig.json | 2 +- 60 files changed, 4115 insertions(+), 1625 deletions(-) delete mode 100644 src.compiler/AlphaTabTransformations.ts delete mode 100644 src.compiler/CloneBuilder.ts delete mode 100644 src.compiler/JsonSerializationBuilder.ts create mode 100644 src.compiler/TranspilerBase.ts create mode 100644 src.compiler/typescript/AlphaTabGenerator.ts create mode 100644 src.compiler/typescript/CloneEmitter.ts create mode 100644 src.compiler/typescript/EmitterBase.ts create mode 100644 src.compiler/typescript/SerializerEmitter.ts create mode 100644 src/generated/CoreSettingsSerializer.ts create mode 100644 src/generated/DisplaySettingsSerializer.ts create mode 100644 src/generated/ImporterSettingsSerializer.ts create mode 100644 src/generated/NotationSettingsSerializer.ts create mode 100644 src/generated/PlayerSettingsSerializer.ts create mode 100644 src/generated/RenderingResourcesSerializer.ts create mode 100644 src/generated/SettingsSerializer.ts create mode 100644 src/generated/SlidePlaybackSettingsSerializer.ts create mode 100644 src/generated/VibratoPlaybackSettingsSerializer.ts create mode 100644 src/generated/model/AutomationCloner.ts create mode 100644 src/generated/model/AutomationSerializer.ts create mode 100644 src/generated/model/BarSerializer.ts create mode 100644 src/generated/model/BeatCloner.ts create mode 100644 src/generated/model/BeatSerializer.ts create mode 100644 src/generated/model/BendPointCloner.ts create mode 100644 src/generated/model/BendPointSerializer.ts create mode 100644 src/generated/model/ChordSerializer.ts create mode 100644 src/generated/model/FermataSerializer.ts create mode 100644 src/generated/model/InstrumentArticulationSerializer.ts create mode 100644 src/generated/model/MasterBarSerializer.ts create mode 100644 src/generated/model/NoteCloner.ts create mode 100644 src/generated/model/NoteSerializer.ts create mode 100644 src/generated/model/PlaybackInformationSerializer.ts create mode 100644 src/generated/model/RenderStylesheetSerializer.ts create mode 100644 src/generated/model/ScoreSerializer.ts create mode 100644 src/generated/model/SectionSerializer.ts create mode 100644 src/generated/model/StaffSerializer.ts create mode 100644 src/generated/model/TrackSerializer.ts create mode 100644 src/generated/model/VoiceSerializer.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 5b8126aeb..2ab4b6d46 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,6 +27,30 @@ "TS_NODE_PROJECT": "tsconfig.build-csharp.json" } }, + + { + "name": "Launch TypeScript Generator", + "type": "node", + "request": "launch", + "args": [ + "src.compiler/typescript/AlphaTabGenerator.ts", + "--project", + "tsconfig.build-csharp.json" + ], + "runtimeArgs": [ + "--nolazy", + "-r", + "ts-node/register" + ], + "cwd": "${workspaceRoot}", + "protocol": "inspector", + "smartStep": false, + "internalConsoleOptions": "openOnSessionStart", + "env": { + "TS_NODE_PROJECT": "tsconfig.build-csharp.json" + } + }, + { "name": "Launch JavaScript Compiler", "type": "node", diff --git a/.vscode/settings.json b/.vscode/settings.json index e302cd919..78af7f1e9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "files.exclude": { "dist/lib.csharp/**": true, - "src.csharp/**": true + "src.csharp/**": true, + "node_modules/**": true } } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 343ee2c2e..211bad9b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,9 +57,9 @@ } }, "@rollup/plugin-commonjs": { - "version": "16.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-16.0.0.tgz", - "integrity": "sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.0.0.tgz", + "integrity": "sha512-/omBIJG1nHQc+bgkYDuLpb/V08QyutP9amOrJRUSlYJZP+b/68gM//D8sxJe3Yry2QnYIr3QjR3x4AlxJEN3GA==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -72,12 +72,12 @@ }, "dependencies": { "resolve": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", - "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { - "is-core-module": "^2.0.0", + "is-core-module": "^2.1.0", "path-parse": "^1.0.6" } } @@ -135,9 +135,9 @@ } }, "@types/jasmine": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.1.tgz", - "integrity": "sha512-eeSCVhBsgwHNS1FmaMu4zrLxfykCTWJMLFZv7lmyrZQjw7foUUXoPu4GukSN9v7JvUw7X+/aDH3kCaymirBSTg==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.6.2.tgz", + "integrity": "sha512-AzfesNFLvOs6Q1mHzIsVJXSeUnqVh4ZHG8ngygKJfbkcSLwzrBVm/LKa+mR8KrOfnWtUL47112gde1MC0IXqpQ==", "dev": true }, "@types/minimatch": { @@ -787,6 +787,12 @@ "vary": "^1" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -1111,9 +1117,9 @@ "dev": true }, "estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true }, "esutils": { @@ -1931,9 +1937,9 @@ "dev": true }, "is-core-module": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", - "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -3074,9 +3080,9 @@ } }, "rollup": { - "version": "2.33.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.1.tgz", - "integrity": "sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==", + "version": "2.35.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.35.1.tgz", + "integrity": "sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==", "dev": true, "requires": { "fsevents": "~2.1.2" @@ -3109,43 +3115,13 @@ } }, "rollup-plugin-dts": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-1.4.13.tgz", - "integrity": "sha512-7mxoQ6PcmCkBE5ZhrjGDL4k42XLy8BkSqpiRi1MipwiGs+7lwi4mQkp2afX+OzzLjJp/TGM8llfe8uayIUhPEw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-dts/-/rollup-plugin-dts-2.0.1.tgz", + "integrity": "sha512-y38NSXIY37YExCumbGBTL5dXg7pL7XD+Kbe98iEHWFN9yiKJf7t4kKBOkml5ylUDjQIXBnNClGDeRktc1T5dmA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "optional": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true, - "optional": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "optional": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - } + "@babel/code-frame": "^7.10.4", + "magic-string": "^0.25.7" } }, "rollup-plugin-license": { @@ -3908,9 +3884,9 @@ } }, "terser": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz", - "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz", + "integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==", "dev": true, "requires": { "commander": "^2.20.0", @@ -3995,12 +3971,13 @@ "dev": true }, "ts-node": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz", - "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", "dev": true, "requires": { "arg": "^4.1.0", + "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "source-map-support": "^0.5.17", @@ -4112,9 +4089,9 @@ "dev": true }, "typescript": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz", - "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", "dev": true }, "ua-parser-js": { diff --git a/package.json b/package.json index 582696341..8032bda04 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,12 @@ "scripts": { "clean": "rimraf dist", "lint": "tslint --project tsconfig.build.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", - "build": "ttsc --project tsconfig.build.json && rollup -c rollup.config.js", + "build": "tsc --project tsconfig.build.json && rollup -c rollup.config.js", "build-ci": "npm run clean && npm run build && npm pack", - "start": "node scripts/setup-playground.js && npm run build && concurrently --kill-others \"ttsc --project tsconfig.build.json --watch\" \"rollup -c rollup.config.js -w\"", - "test": "ttsc --project tsconfig.json && concurrently --kill-others \"ttsc --project tsconfig.json -w\" \"karma start karma.conf.js --browsers Chrome --no-single-run --reporters spec,kjhtml\"", - "test-ci": "ttsc --project tsconfig.json && karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters spec", + "start": "node scripts/setup-playground.js && npm run build && concurrently --kill-others \"tsc --project tsconfig.build.json --watch\" \"rollup -c rollup.config.js -w\"", + "test": "tsc --project tsconfig.json && concurrently --kill-others \"tsc --project tsconfig.json -w\" \"karma start karma.conf.js --browsers Chrome --no-single-run --reporters spec,kjhtml\"", + "test-ci": "tsc --project tsconfig.json && karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters spec", + "generate-typescript": "rimraf src/generated && ts-node --project tsconfig.build-csharp.json src.compiler/typescript/AlphaTabGenerator.ts --project tsconfig.build-csharp.json", "generate-csharp": "ts-node --project tsconfig.build-csharp.json src.compiler/csharp/CSharpTranspiler.ts --project tsconfig.build-csharp.json", "build-csharp": "npm run generate-csharp && cd src.csharp && dotnet build -c Release", "build-csharp-ci": "npm run clean && npm run generate-csharp && cd src.csharp && dotnet build -c Release", @@ -40,8 +41,8 @@ "test-csharp-ci": "cd src.csharp && dotnet test" }, "devDependencies": { - "@rollup/plugin-commonjs": "^16.0.0", - "@types/jasmine": "^3.6.1", + "@rollup/plugin-commonjs": "^17.0.0", + "@types/jasmine": "^3.6.2", "concurrently": "^5.3.0", "cors": "^2.8.5", "fs-extra": "^9.0.1", @@ -56,19 +57,19 @@ "lodash": "^4.17.20", "multer": "^1.4.2", "rimraf": "^3.0.2", - "rollup": "^2.33.1", + "rollup": "^2.35.1", "rollup-plugin-copy": "^3.3.0", - "rollup-plugin-dts": "^1.4.13", + "rollup-plugin-dts": "^2.0.1", "rollup-plugin-license": "^2.2.0", "rollup-plugin-serve": "^1.1.0", "rollup-plugin-terser": "^7.0.2", - "terser": "^5.3.8", - "ts-node": "^9.0.0", + "terser": "^5.5.1", + "ts-node": "^9.1.1", "tslint": "^6.1.3", "tslint-config-prettier": "^1.15.0", "tslint-config-standard": "^9.0.0", "ttypescript": "^1.5.12", - "typescript": "^4.0.5" + "typescript": "^4.1.3" }, "files": [ "/dist/alphaTab.js", diff --git a/src.compiler/AlphaTabTransformations.ts b/src.compiler/AlphaTabTransformations.ts deleted file mode 100644 index ad8db2bb4..000000000 --- a/src.compiler/AlphaTabTransformations.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as ts from 'typescript'; -import { rewriteClassForCloneable } from './CloneBuilder' -import { rewriteClassForJsonSerialization } from './JsonSerializationBuilder' - -export default function (program: ts.Program) { - return (ctx: ts.TransformationContext) => { - return (sourceFile: ts.SourceFile) => { - function visitor(node: ts.Node): ts.Node { - if (ts.isClassDeclaration(node)) { - const isClonable = ts.getJSDocTags(node).find(t => t.tagName.text === 'cloneable'); - const isJson = ts.getJSDocTags(node).find(t => t.tagName.text === 'json'); - if (isClonable) { - node = rewriteClassForCloneable(node, ctx.factory, program.getTypeChecker()); - } - - if (isJson) { - node = rewriteClassForJsonSerialization(program, node as ts.ClassDeclaration, sourceFile, ctx.factory); - } - } - - return node; - } - - return ts.visitEachChild(sourceFile, visitor, ctx); - }; - }; -} diff --git a/src.compiler/BuilderHelpers.ts b/src.compiler/BuilderHelpers.ts index b5347bf06..afafa6b74 100644 --- a/src.compiler/BuilderHelpers.ts +++ b/src.compiler/BuilderHelpers.ts @@ -1,6 +1,17 @@ +import { indexOf } from 'lodash'; import * as ts from 'typescript'; -export function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNode) { +export function addNewLines(stmts: ts.Statement[]) { + return stmts.map(stmt => ts.addSyntheticTrailingComment(stmt, ts.SyntaxKind.SingleLineCommentTrivia, '', true)); +} +export function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNode | undefined) { + if(!node) { + return { + isNullable: false, + type: {} as ts.Type + }; + } + let isNullable = false; let type: ts.Type | null = null; if (ts.isUnionTypeNode(node)) { @@ -21,7 +32,7 @@ export function getTypeWithNullableInfo(checker: ts.TypeChecker, node: ts.TypeNo return { isNullable, - type + type: type as ts.Type }; } @@ -43,7 +54,11 @@ export function unwrapArrayItemType(type: ts.Type, typeChecker: ts.TypeChecker): } -export function isPrimitiveType(type: ts.Type) { +export function isPrimitiveType(type: ts.Type | null) { + if (!type) { + return false; + } + if (hasFlag(type, ts.TypeFlags.Number)) { return true; } @@ -63,6 +78,18 @@ export function isPrimitiveType(type: ts.Type) { return isEnumType(type); } +export function isNumberType(type: ts.Type | null) { + if (!type) { + return false; + } + + if (hasFlag(type, ts.TypeFlags.Number)) { + return true; + } + + return false; +} + export function isEnumType(type: ts.Type) { // if for some reason this returns true... if (hasFlag(type, ts.TypeFlags.Enum)) return true; @@ -81,13 +108,13 @@ export function wrapToNonNull(isNullableType: boolean, expr: ts.Expression, fact } export function isTypedArray(type: ts.Type) { - return type.symbol.members.has(ts.escapeLeadingUnderscores('slice')); + return !!type.symbol.members?.has(ts.escapeLeadingUnderscores('slice')); } export function hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean { return (type.flags & flag) === flag; } -export function isMap(type: ts.Type): boolean { - return type.symbol.name === 'Map'; +export function isMap(type: ts.Type | null): boolean { + return !!(type && type.symbol?.name === 'Map'); } \ No newline at end of file diff --git a/src.compiler/CloneBuilder.ts b/src.compiler/CloneBuilder.ts deleted file mode 100644 index 244caf05f..000000000 --- a/src.compiler/CloneBuilder.ts +++ /dev/null @@ -1,305 +0,0 @@ -import * as ts from 'typescript'; -import { getTypeWithNullableInfo } from './BuilderHelpers'; -import { unwrapArrayItemType } from './BuilderHelpers'; - -function isClonable(type: ts.Type): boolean { - if (!type.symbol) { - return false; - } - - const declaration = type.symbol.valueDeclaration; - if (declaration) { - return !!ts.getJSDocTags(declaration).find(t => t.tagName.text === 'cloneable'); - } - - return false; -} - -function generateClonePropertyStatements(prop: ts.PropertyDeclaration, typeChecker: ts.TypeChecker, factory: ts.NodeFactory): ts.Statement[] { - const propertyType = getTypeWithNullableInfo(typeChecker, prop.type); - - const propertyName = (prop.name as ts.Identifier).text; - - function assign(expr: ts.Expression) { - return [factory.createExpressionStatement( - factory.createAssignment( - factory.createPropertyAccessExpression( - factory.createIdentifier('clone'), - propertyName - ), - expr - ) - )]; - } - - const arrayItemType = unwrapArrayItemType(propertyType.type, typeChecker); - if (arrayItemType) { - if (isClonable(arrayItemType)) { - const collectionAddMethod = ts.getJSDocTags(prop) - .filter(t => t.tagName.text === 'clone_add') - .map(t => t.comment ?? "")[0]; - - const loopItems = [ - ...assign(factory.createArrayLiteralExpression(undefined)), - - factory.createForOfStatement( - undefined, - factory.createVariableDeclarationList( - [factory.createVariableDeclaration('i')], - ts.NodeFlags.Const - ), - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - factory.createExpressionStatement( - collectionAddMethod - // clone.addProp(i.clone()) - ? factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('clone'), - collectionAddMethod - ), - undefined, - [factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('i'), - 'clone' - ), - undefined, - [] - ), factory.createIdentifier('i')] - ) - // clone.prop.push(i.clone() - : factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('clone'), - propertyName - ), - 'push' - ), - undefined, - [factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('i'), - 'clone' - ), - undefined, - [] - )] - ) - ) - )]; - - if (propertyType.isNullable) { - // if(this.prop) { - // clone.prop = []; - // for(const i of this.prop) { clone.addProp(i.clone()); } - // // or - // for(const i of this.prop) { clone.prop.add(i.clone()); } - // } - return [factory.createIfStatement( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - factory.createBlock( - loopItems - ), - undefined - )]; - } else { - // clone.prop = []; - // for(const i of this.prop) { clone.addProp(i.clone()); } - // // or - // for(const i of this.prop) { clone.prop.add(i.clone()); } - return loopItems; - } - } else { - const sliceCall = - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - 'slice' - ), - undefined, - [] - ); - - if (propertyType.isNullable) { - return assign( - factory.createConditionalExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - factory.createToken(ts.SyntaxKind.QuestionToken), - sliceCall, - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() - ) - ); - } else { - // clone.prop = this.prop.splice() - return assign(sliceCall); - } - } - } else { - if (isClonable(propertyType.type)) { - // clone.prop = this.prop ? this.prop.clone() : null - return assign( - factory.createConditionalExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ), - 'clone' - ), - undefined, - [] - ), - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() - ) - ); - } else { - // clone.prop = this.prop - return assign( - factory.createPropertyAccessExpression( - factory.createThis(), - propertyName - ) - ); - } - } -} - -function generateCloneBody(classDeclaration: ts.ClassDeclaration, propertiesToSerialize: ts.PropertyDeclaration[], factory: ts.NodeFactory, typeChecker: ts.TypeChecker): ts.Block { - - const bodyStatements = propertiesToSerialize.reduce((stmts, prop) => { - stmts.push(...generateClonePropertyStatements(prop, typeChecker, factory)); - return stmts; - }, new Array()); - - return factory.createBlock([ - // const clone = new Type(); - factory.createVariableStatement( - [factory.createModifier(ts.SyntaxKind.ConstKeyword)], - [ - factory.createVariableDeclaration( - 'clone', - undefined, - undefined, - factory.createNewExpression(factory.createIdentifier(classDeclaration.name.text), [], []) - ) - ] - ), - ...bodyStatements, - // return json; - factory.createReturnStatement(factory.createIdentifier('clone')) - ]); -} - -function isCloneMember(propertyDeclaration: ts.PropertyDeclaration) { - if (propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.ReadonlyKeyword)) { - return false; - } - - if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.PublicKeyword)) { - return false; - } - - if (ts.getJSDocTags(propertyDeclaration).find(t => t.tagName.text === 'clone_ignore')) { - return false; - } - - return true; -} - -export function rewriteClassForCloneable( - classDeclaration: ts.ClassDeclaration, - factory: ts.NodeFactory, - typeChecker: ts.TypeChecker -): ts.ClassDeclaration { - console.debug(`Rewriting ${classDeclaration.name.escapedText} for cloning`); - let cloneMethod: ts.MethodDeclaration = undefined; - let propertiesToSerialize: ts.PropertyDeclaration[] = []; - - var newMembers = []; - - // collect class state - classDeclaration.members.forEach(member => { - if (ts.isPropertyDeclaration(member)) { - const propertyDeclaration = member as ts.PropertyDeclaration; - if (isCloneMember(propertyDeclaration)) { - propertiesToSerialize.push(propertyDeclaration); - } - newMembers.push(member); - } else if (ts.isMethodDeclaration(member)) { - if (ts.isIdentifier(member.name)) { - const methodName = (member.name as ts.Identifier).escapedText; - switch (methodName) { - case 'clone': - cloneMethod = member; - break; - default: - newMembers.push(member); - break; - } - } - } else { - newMembers.push(member); - } - }); - - if (!cloneMethod) { - cloneMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword)], - undefined, - 'clone', - undefined, - undefined, - [], - factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - undefined - ); - } - - cloneMethod = factory.updateMethodDeclaration( - cloneMethod, - cloneMethod.decorators, - cloneMethod.modifiers, - cloneMethod.asteriskToken, - cloneMethod.name, - cloneMethod.questionToken, - cloneMethod.typeParameters, - cloneMethod.parameters, - cloneMethod.type, - generateCloneBody(classDeclaration, propertiesToSerialize, factory, typeChecker) - ) - newMembers.push(cloneMethod); - - console.debug(`Rewriting ${classDeclaration.name.escapedText} done`); - - return factory.updateClassDeclaration( - classDeclaration, - classDeclaration.decorators, - classDeclaration.modifiers, - classDeclaration.name, - classDeclaration.typeParameters, - classDeclaration.heritageClauses, - newMembers - ); -} \ No newline at end of file diff --git a/src.compiler/JsonSerializationBuilder.ts b/src.compiler/JsonSerializationBuilder.ts deleted file mode 100644 index 0475dcc23..000000000 --- a/src.compiler/JsonSerializationBuilder.ts +++ /dev/null @@ -1,1043 +0,0 @@ -import { slice } from 'lodash'; -import * as ts from 'typescript'; -import { getTypeWithNullableInfo } from './BuilderHelpers'; -import { isPrimitiveType } from './BuilderHelpers'; -import { isEnumType } from './BuilderHelpers'; -import { wrapToNonNull } from './BuilderHelpers'; -import { isTypedArray } from './BuilderHelpers'; -import { isMap } from './BuilderHelpers'; -import { unwrapArrayItemType } from './BuilderHelpers'; -; -interface JsonProperty { - property: ts.PropertyDeclaration; - jsonNames: string[]; -} - -function isImmutable(type: ts.Type): boolean { - const declaration = type.symbol.valueDeclaration; - if (declaration) { - return !!ts.getJSDocTags(declaration).find(t => t.tagName.text === 'json_immutable'); - } - - return false; -} - -function generateToJsonBodyForClass( - factory: ts.NodeFactory -): ts.Block { - return factory.createBlock([ - // const json:any = {}; - factory.createVariableStatement( - [factory.createModifier(ts.SyntaxKind.ConstKeyword)], - [ - factory.createVariableDeclaration( - 'json', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - factory.createObjectLiteralExpression() - ) - ] - ), - - // obj.fillToJson(json) - factory.createExpressionStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('obj'), 'fillToJson'), - [], - [factory.createIdentifier('json')] - ) - ), - - // return json; - factory.createReturnStatement(factory.createIdentifier('json')) - ]); -} -function generateFillToJsonBodyForClass( - program: ts.Program, - propertiesToSerialize: JsonProperty[], - factory: ts.NodeFactory -): ts.Block { - const statements: ts.Statement[] = []; - - for (let prop of propertiesToSerialize) { - const fieldName = (prop.property.name as ts.Identifier).text; - const jsonName = prop.jsonNames.filter(n => n !== '')[0]; - - const accessJsonName = function (): ts.Expression { - return factory.createPropertyAccessExpression(factory.createIdentifier('json'), jsonName); - }; - const accessField = function (): ts.Expression { - return factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)); - }; - - const assignToJsonName = function (value: ts.Expression): ts.Statement { - return factory.createExpressionStatement(factory.createAssignment(accessJsonName(), value)); - }; - - if (jsonName) { - const typeChecker = program.getTypeChecker(); - const type = getTypeWithNullableInfo(typeChecker, prop.property.type); - if (isPrimitiveType(type.type)) { - // json.jsonName = this.fieldName - statements.push(assignToJsonName(accessField())); - } else if (isTypedArray(type.type)) { - const arrayItemType = unwrapArrayItemType(type.type, typeChecker); - if (!arrayItemType || isPrimitiveType(arrayItemType)) { - // json.jsonName = this.fieldName ? this.fieldName.slice() : null - if (type.isNullable) { - statements.push( - assignToJsonName( - factory.createConditionalExpression( - accessField(), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() - ) - ) - ); - } else { - statements.push( - assignToJsonName(factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) - ); - } - } else { - // avoid the type being elided - factory.createNotEmittedStatement(factory.createExpressionStatement( - factory.createIdentifier(arrayItemType.symbol.name) - )); - - // json.jsonName = this.fieldName ? this.fieldName.map($li => TypeName.toJson($li)) : null - const mapCall = factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'map'), undefined, [ - factory.createArrowFunction( - undefined, - undefined, - [factory.createParameterDeclaration(undefined, undefined, undefined, '$li')], - undefined, factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'toJson'), - undefined, - [factory.createIdentifier('$li')] - ) - ), - ]); - if (type.isNullable) { - statements.push( - assignToJsonName( - factory.createConditionalExpression( - accessField(), - factory.createToken(ts.SyntaxKind.QuestionToken), - mapCall, - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() - ) - ) - ); - } else { - statements.push( - assignToJsonName(mapCall) - ); - } - } - } else if (isMap(type.type)) { - const mapType = type.type as ts.TypeReference; - if (!isPrimitiveType(mapType.typeArguments[0])) { - throw new Error('only Map maps are supported extend if needed!'); - } - // json.jsonName = { } as any; - // this.fieldName.forEach((val, key) => (json.jsonName as any)[key] = val)) - statements.push( - assignToJsonName( - factory.createAsExpression( - factory.createObjectLiteralExpression(), - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ) - ); - - // avoid the type being elided - - if (!isPrimitiveType(mapType.typeArguments[1])) { - factory.createNotEmittedStatement(factory.createExpressionStatement( - factory.createIdentifier(mapType.typeArguments[1].symbol.name) - )); - } - - const mapValue = isPrimitiveType(mapType.typeArguments[1]) - ? factory.createIdentifier('$mv') - : factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier(mapType.typeArguments[1].symbol.name), 'toJson'), - undefined, - [factory.createIdentifier('$mv')] - ); - - statements.push( - factory.createExpressionStatement( - factory.createCallExpression(factory.createPropertyAccessExpression(accessField(), 'forEach'), undefined, [ - factory.createArrowFunction( - undefined, - undefined, - [ - factory.createParameterDeclaration(undefined, undefined, undefined, '$mv'), - factory.createParameterDeclaration(undefined, undefined, undefined, '$mk') - ], - undefined, - factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - factory.createBlock([ - factory.createExpressionStatement( - factory.createAssignment( - factory.createElementAccessExpression( - factory.createAsExpression( - accessJsonName(), - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ), - factory.createIdentifier('$mk') - ), - mapValue - ) - ) - ]) - ) - ]) - ) - ); - } else if (isImmutable(type.type)) { - // json.jsonName = TypeName.toJson(this.fieldName); - statements.push( - assignToJsonName( - wrapToNonNull( - type.isNullable, - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'toJson'), - [], - [accessField()] - ), - factory - ) - ) - ); - } else { - // not nullable: - // if(json.jsonName) { - // this.fieldName.fillToJson(json.jsonName) - // } else { - // json.jsonName = TypeName.toJson(this.fieldName)!; - // } - - // nullable: - // if(json.jsonName) { - // if(this.fieldName) this.fieldName.fillToJson(json.jsonName) - // } else { - // json.jsonName = TypeName.toJson(this.fieldName); - // } - - // this.field.fillToJson(json.jsonName) - let fillToJsonStatent: ts.Statement = factory.createExpressionStatement( - factory.createCallExpression( - // this.field.fillToJson - factory.createPropertyAccessExpression(accessField(), 'fillToJson'), - [], - [accessJsonName()] - ) - ); - if (type.isNullable) { - fillToJsonStatent = factory.createIfStatement(accessField(), fillToJsonStatent); - } - - statements.push( - factory.createIfStatement( - // if(json.jsonName) - accessJsonName(), - // this.field.fillToJson(json.jsonName) - fillToJsonStatent, - // else json.jsonName = ... - assignToJsonName( - wrapToNonNull( - type.isNullable, - factory.createCallExpression( - // TypeName.toJson - factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'toJson'), - [], - [accessField()] - ), - factory - ), - ) - ) - ); - } - } - } - - return factory.createBlock(statements); -} -function generateFromJsonBodyForClass( - classDeclaration: ts.ClassDeclaration, - factory: ts.NodeFactory -): ts.Block { - const statements: ts.Statement[] = []; - // if(!json) return null; - statements.push( - factory.createIfStatement( - factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, factory.createIdentifier('json')), - factory.createReturnStatement(factory.createNull()) - ) - ); - - // const obj = new Type(); - statements.push( - factory.createVariableStatement( - [factory.createModifier(ts.SyntaxKind.ConstKeyword)], - [ - factory.createVariableDeclaration( - 'obj', - undefined, - undefined, - factory.createNewExpression(factory.createIdentifier(classDeclaration.name.text), [], []) - ) - ] - ) - ); - - // obj.fillFromJson(json); - statements.push( - factory.createExpressionStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('obj'), 'fillFromJson'), - [], - [factory.createIdentifier('json')] - ) - ) - ); - - // return obj; - statements.push( - // return json; - factory.createReturnStatement(factory.createIdentifier('obj')) - ); - - return factory.createBlock(statements); -} -function generateFillFromJsonBodyForClass( - factory: ts.NodeFactory -): ts.Block { - return factory.createBlock([ - factory.createIfStatement( - // if(json) for($k in json) { this.setProperty($k.toLowerCase(), json[$k]) } - factory.createIdentifier('json'), - factory.createForInStatement( - factory.createVariableDeclarationList([factory.createVariableDeclaration('$k')], ts.NodeFlags.Const), - factory.createIdentifier('json'), - factory.createExpressionStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createThis(), 'setProperty'), - [], - [ - // $k.toLowerCase(), - factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('$k'), 'toLowerCase'), [], []), - // json[$k] - factory.createElementAccessExpression(factory.createIdentifier('json'), factory.createIdentifier('$k')) - ] - ) - ) - ) - ) - ]); -} - -function createEnumMapping(value: string, type: ts.Type, factory: ts.NodeFactory): ts.Expression { - // isNan(parseInt(value)) ? Enum[Object.keys(Enum).find($k => $k.toLowerCase() === value.toLowerCase()] : parseInt(value) - return factory.createConditionalExpression( - factory.createCallExpression(factory.createIdentifier('isNaN'), undefined, [ - factory.createCallExpression(factory.createIdentifier('parseInt'), undefined, [factory.createIdentifier(value)]) - ]), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createElementAccessExpression( - factory.createIdentifier(type.symbol.name), - factory.createCallExpression( - // Object.keys(EnumName).find - factory.createPropertyAccessExpression( - // Object.keys(EnumName) - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('Object'), 'keys'), - [], - [factory.createIdentifier(type.symbol.name)] - ), - 'find' - ), - [], - [ - factory.createArrowFunction( - [], - [], - [factory.createParameterDeclaration(undefined, undefined, undefined, '$k')], - undefined, - factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - factory.createBinaryExpression( - factory.createCallExpression( - // $.toLowerCase() - factory.createPropertyAccessExpression(factory.createIdentifier('$k'), 'toLowerCase'), - [], - [] - ), - // === - factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), - // value.toLowerCase() - factory.createCallExpression( - // $.toLowerCase() - factory.createPropertyAccessExpression(factory.createIdentifier(value), 'toLowerCase'), - [], - [] - ) - ) - ) - ] - ) - ), - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createCallExpression(factory.createIdentifier('parseInt'), undefined, [factory.createIdentifier(value)]) - ); -} - -function generateSetPropertyMethodBodyForClass( - program: ts.Program, - propertiesToSerialize: JsonProperty[], - factory: ts.NodeFactory -): ts.Block { - const statements: ts.Statement[] = []; - const cases: ts.CaseOrDefaultClause[] = []; - - const typeChecker = program.getTypeChecker(); - for (const prop of propertiesToSerialize) { - const jsonNames = prop.jsonNames.map(j => j.toLowerCase()); - const caseValues: string[] = jsonNames.filter(j => j !== ''); - const fieldName = (prop.property.name as ts.Identifier).text; - - const caseStatements: ts.Statement[] = []; - - const type = getTypeWithNullableInfo(typeChecker, prop.property.type); - - const assignField = function (expr: ts.Expression): ts.Statement { - return factory.createExpressionStatement( - factory.createAssignment(factory.createPropertyAccessExpression(factory.createThis(), fieldName), expr) - ); - }; - - if (isEnumType(type.type)) { - // this.fieldName = enummapping - // return true; - if (type.isNullable) { - caseStatements.push(assignField( - factory.createConditionalExpression( - factory.createBinaryExpression( - factory.createIdentifier('value'), - ts.SyntaxKind.EqualsEqualsEqualsToken, - factory.createNull() - ), - factory.createToken(ts.SyntaxKind.QuestionToken), - factory.createNull(), - factory.createToken(ts.SyntaxKind.ColonToken), - createEnumMapping('value', type.type, factory) - ) - )); - } else { - caseStatements.push(assignField(createEnumMapping('value', type.type, factory))); - } - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } else if (isPrimitiveType(type.type)) { - // this.fieldName = value - // return true; - caseStatements.push(assignField(factory.createIdentifier('value'))); - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } else if (isTypedArray(type.type)) { - const arrayItemType = unwrapArrayItemType(type.type, typeChecker); - if (!arrayItemType || isPrimitiveType(arrayItemType)) { - // nullable: - // this.fieldName = value ? value.slice() : null - // return true; - - // not nullable: - // this.fieldName = value.slice() - // return true; - const sliceCall = factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'slice'), [], []); - if (type.isNullable) { - caseStatements.push( - assignField( - factory.createConditionalExpression( - factory.createIdentifier('value'), - factory.createToken(ts.SyntaxKind.QuestionToken), - sliceCall, - factory.createToken(ts.SyntaxKind.ColonToken), - factory.createNull() - ) - ) - ); - } else { - caseStatements.push( - assignField(sliceCall) - ); - } - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } else { - const collectionAddMethod = ts.getJSDocTags(prop.property) - .filter(t => t.tagName.text === 'json_add') - .map(t => t.comment ?? "")[0]; - - // this.fieldName = []; - // for(const $li of value) { - // this.addFieldName(Type.FromJson($li)); - // } - // or - // for(const $li of value) { - // this.fieldName.push(Type.FromJson($li)); - // } - const loopItems = [ - assignField(factory.createArrayLiteralExpression(undefined)), - factory.createForOfStatement( - undefined, - factory.createVariableDeclarationList( - [factory.createVariableDeclaration('$li')], - ts.NodeFlags.Const - ), - factory.createIdentifier('value'), - factory.createExpressionStatement( - collectionAddMethod - // this.addFieldName(TypeName.FromJson($li)) - ? factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - collectionAddMethod - ), - undefined, - [factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'fromJson'), - [], - [factory.createIdentifier('$li')] - )] - ) - // this.fieldName.push(TypeName.FromJson($li)) - : factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression( - factory.createThis(), - fieldName - ), - 'push' - ), - undefined, - [factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier(arrayItemType.symbol.name), 'fromJson'), - [], - [factory.createIdentifier('$li')] - )] - ) - ) - )]; - - if (type.isNullable) { - caseStatements.push(factory.createIfStatement( - factory.createIdentifier('value'), - factory.createBlock(loopItems) - )); - } else { - caseStatements.push(...loopItems); - } - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } - - } else if (isMap(type.type)) { - // this.fieldName = new Map(); - // for(let key in value) { - // if(value.hasOwnProperty(key) this.fieldName.set(, value[key]); - // } - // or - // for(let key in value) { - // if(value.hasOwnProperty(key) this.addFieldName(, value[key]); - // } - // return true; - - const mapType = type.type as ts.TypeReference; - if (!isPrimitiveType(mapType.typeArguments[0])) { - throw new Error('only Map maps are supported extend if needed!'); - } - - const mapKey = isEnumType(mapType.typeArguments[0]) - ? createEnumMapping('$mk', mapType.typeArguments![0], factory) - : factory.createIdentifier('$mk'); - - let mapValue: ts.Expression = factory.createElementAccessExpression(factory.createIdentifier('value'), factory.createIdentifier('$mk')); - if (!isPrimitiveType(mapType.typeArguments[1])) { - mapValue = factory.createCallExpression( - // TypeName.fromJson - factory.createPropertyAccessExpression(factory.createIdentifier(mapType.typeArguments[1].symbol.name), 'fromJson'), - [], - [mapValue] - ); - } - - const collectionAddMethod = ts.getJSDocTags(prop.property) - .filter(t => t.tagName.text === 'json_add') - .map(t => t.comment ?? "")[0]; - - caseStatements.push(assignField(factory.createNewExpression(factory.createIdentifier('Map'), undefined, []))); - caseStatements.push( - factory.createForInStatement( - factory.createVariableDeclarationList( - [factory.createVariableDeclaration(factory.createIdentifier('$mk'), undefined, undefined)], - ts.NodeFlags.Let - ), - factory.createIdentifier('value'), - factory.createIfStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('value'), 'hasOwnProperty'), - undefined, - [factory.createIdentifier('$mk')] - ), - factory.createExpressionStatement( - factory.createCallExpression( - collectionAddMethod - ? factory.createPropertyAccessExpression(factory.createThis(), collectionAddMethod) - : factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression(factory.createThis(), factory.createIdentifier(fieldName)), - factory.createIdentifier('set') - ), - undefined, - [ - mapKey, - mapValue - ] - ) - ) - ) - ) - ); - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } else if (isImmutable(type.type)) { - // this.fieldName = TypeName.fromJson(value)! - // return true; - caseStatements.push( - assignField( - wrapToNonNull( - type.isNullable, - factory.createCallExpression( - // TypeName.fromJson - factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'fromJson'), - [], - [factory.createIdentifier('value')] - ), - factory - ) - ) - ); - caseStatements.push(factory.createReturnStatement(factory.createTrue())); - } else { - // for complex types it is a bit more tricky - // if the property matches exactly, we use fromJson - // if the property starts with the field name, we try to set a sub-property - const jsonNameArray = factory.createArrayLiteralExpression(jsonNames.map(n => factory.createStringLiteral(n))); - - statements.push( - factory.createIfStatement( - // if(["", "core"].indexOf(property) >= 0) - factory.createBinaryExpression( - factory.createCallExpression( - factory.createPropertyAccessExpression(jsonNameArray, 'indexOf'), - [], - [factory.createIdentifier('property')] - ), - ts.SyntaxKind.GreaterThanEqualsToken, - factory.createNumericLiteral('0') - ), - factory.createBlock([ - // if(this.field) { - // this.field.fillFromJson(value); - // } else { - // this.field = TypeName.fromJson(value); - // } - // return true; - factory.createIfStatement( - factory.createPropertyAccessExpression(factory.createThis(), fieldName), - factory.createExpressionStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression(factory.createThis(), fieldName), - 'fillFromJson' - ), - [], - [factory.createIdentifier('value')] - ) - ), - assignField( - wrapToNonNull( - type.isNullable, - factory.createCallExpression( - // TypeName.fromJson - factory.createPropertyAccessExpression(factory.createIdentifier(type.type.symbol.name), 'fromJson'), - [], - [factory.createIdentifier('value')] - ), - factory - ) - ) - ), - factory.createReturnStatement(factory.createTrue()) - ]), - factory.createBlock([ - // for(const candidate of ["", "core"]) { - // if(candidate.indexOf(property) === 0) { - // if(!this.field) { this.field = new FieldType(); } - // if(this.field.setProperty(property.substring(candidate.length), value)) return true; - // } - // } - factory.createForOfStatement( - undefined, - factory.createVariableDeclarationList([factory.createVariableDeclaration('$c')], ts.NodeFlags.Const), - jsonNameArray, - factory.createIfStatement( - factory.createBinaryExpression( - factory.createCallExpression( - factory.createPropertyAccessExpression(factory.createIdentifier('property'), 'indexOf'), - [], - [factory.createIdentifier('$c')] - ), - ts.SyntaxKind.EqualsEqualsEqualsToken, - factory.createNumericLiteral('0') - ), - factory.createBlock([ - factory.createIfStatement( - factory.createPrefixUnaryExpression( - ts.SyntaxKind.ExclamationToken, - factory.createPropertyAccessExpression(factory.createThis(), fieldName) - ), - assignField(factory.createNewExpression(factory.createIdentifier(type.type.symbol.name), [], [])) - ), - factory.createIfStatement( - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createPropertyAccessExpression(factory.createThis(), fieldName), - 'setProperty' - ), - [], - [ - factory.createCallExpression( - factory.createPropertyAccessExpression( - factory.createIdentifier('property'), - 'substring' - ), - [], - [factory.createPropertyAccessExpression(factory.createIdentifier('$c'), 'length')] - ), - factory.createIdentifier('value') - ] - ), - factory.createReturnStatement(factory.createTrue()) - ) - ]) - ) - ) - ]) - ) - ); - } - - if (caseStatements.length > 0) { - for (let i = 0; i < caseValues.length; i++) { - cases.push( - factory.createCaseClause( - factory.createStringLiteral(caseValues[i]), - // last case gets the statements, others are fall through - i < caseValues.length - 1 ? [] : caseStatements - ) - ); - } - } - } - - const switchExpr = factory.createSwitchStatement(factory.createIdentifier('property'), factory.createCaseBlock(cases)); - statements.unshift(switchExpr); - statements.push(factory.createReturnStatement(factory.createFalse())); - - return factory.createBlock(statements); -} - -export function rewriteClassForJsonSerialization( - program: ts.Program, - classDeclaration: ts.ClassDeclaration, - sourceFile: ts.SourceFile, - factory: ts.NodeFactory -): ts.ClassDeclaration { - console.debug(`Rewriting ${classDeclaration.name.escapedText} for JSON serialization`); - let toJsonMethod: ts.MethodDeclaration = undefined; - let fromJsonMethod: ts.MethodDeclaration = undefined; - let fillToJsonMethod: ts.MethodDeclaration = undefined; - let fillFromJsonMethod: ts.MethodDeclaration = undefined; - let setPropertyMethod: ts.MethodDeclaration = undefined; - - let propertiesToSerialize: JsonProperty[] = []; - - var newMembers = []; - - // collect class state - classDeclaration.members.forEach(member => { - if (ts.isPropertyDeclaration(member)) { - const propertyDeclaration = member as ts.PropertyDeclaration; - if (!propertyDeclaration.modifiers.find(m => - m.kind === ts.SyntaxKind.StaticKeyword || - m.kind === ts.SyntaxKind.PrivateKeyword || - m.kind === ts.SyntaxKind.ReadonlyKeyword)) { - const jsonNames = [member.name.getText(sourceFile)]; - - if (ts.getJSDocTags(member).find(t => t.tagName.text === 'json_on_parent')) { - jsonNames.push(''); - } - - if (!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_ignore')) { - propertiesToSerialize.push({ - property: propertyDeclaration, - jsonNames: jsonNames - }); - } - } - newMembers.push(member); - } else if (ts.isMethodDeclaration(member)) { - if (ts.isIdentifier(member.name)) { - const methodName = (member.name as ts.Identifier).escapedText; - switch (methodName) { - case 'toJson': - toJsonMethod = member; - break; - case 'fromJson': - fromJsonMethod = member; - break; - case 'fillToJson': - fillToJsonMethod = member; - break; - case 'fillFromJson': - fillFromJsonMethod = member; - break; - case 'setProperty': - setPropertyMethod = member; - break; - default: - newMembers.push(member); - break; - } - } - } else { - newMembers.push(member); - } - }); - - if (!toJsonMethod) { - toJsonMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword), factory.createModifier(ts.SyntaxKind.StaticKeyword)], - undefined, - 'toJson', - undefined, - undefined, - [ - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'obj', - undefined, - factory.createTypeReferenceNode(classDeclaration.name, []) - ) - ], - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - undefined - ); - } - - if (!fillToJsonMethod) { - fillToJsonMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword)], - undefined, - 'fillToJson', - undefined, - undefined, - [ - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'json', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ], - factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) - ); - } - - if (!fromJsonMethod) { - fromJsonMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword), factory.createModifier(ts.SyntaxKind.StaticKeyword)], - undefined, - 'fromJson', - undefined, - undefined, - [ - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'json', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ], - factory.createTypeReferenceNode(classDeclaration.name, []), - factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) - ); - } - - if (!fillFromJsonMethod) { - fillFromJsonMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword)], - undefined, - 'fillFromJson', - undefined, - undefined, - [ - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'json', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ], - factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) - ); - } - - if (!setPropertyMethod) { - setPropertyMethod = factory.createMethodDeclaration( - undefined, - [factory.createModifier(ts.SyntaxKind.PublicKeyword)], - undefined, - 'setProperty', - undefined, - undefined, - [ - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'property', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) - ), - factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'value', - undefined, - factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ], - factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), - factory.createBlock([factory.createThrowStatement(factory.createStringLiteral('todo'))]) - ); - } - - function updateMethodBody( - method: ts.MethodDeclaration, - paramNames: string[], - body: ts.Block, - factory: ts.NodeFactory - ): ts.MethodDeclaration { - if (!method) { - return; - } - const parameters = method.parameters.map((v, i) => - factory.createParameterDeclaration( - method.parameters[i].decorators, - method.parameters[i].modifiers, - method.parameters[i].dotDotDotToken, - i < paramNames.length ? paramNames[i] : method.parameters[0].name, - method.parameters[i].questionToken, - method.parameters[i].type, - method.parameters[i].initializer - ) - ); - - return factory.updateMethodDeclaration( - method, - method.decorators, - method.modifiers, - method.asteriskToken, - method.name, - method.questionToken, - method.typeParameters, - parameters, - method.type, - body - ); - } - - // let requiredTypes:ts.Identifier = []; - - toJsonMethod = updateMethodBody( - toJsonMethod, - ['obj'], - generateToJsonBodyForClass(factory), - factory - ); - - fillToJsonMethod = updateMethodBody( - fillToJsonMethod, - ['json'], - generateFillToJsonBodyForClass(program, propertiesToSerialize, factory), - factory - ); - - fromJsonMethod = updateMethodBody( - fromJsonMethod, - ['json'], - generateFromJsonBodyForClass(classDeclaration, factory), - factory - ); - - fillFromJsonMethod = updateMethodBody( - fillFromJsonMethod, - ['json'], - generateFillFromJsonBodyForClass(factory), - factory - ); - - setPropertyMethod = updateMethodBody( - setPropertyMethod, - ['property', 'value'], - generateSetPropertyMethodBodyForClass(program, propertiesToSerialize, factory), - factory - ); - - newMembers.push(toJsonMethod); - newMembers.push(fillToJsonMethod); - newMembers.push(fromJsonMethod); - newMembers.push(fillFromJsonMethod); - newMembers.push(setPropertyMethod); - - console.debug(`Rewriting ${classDeclaration.name.escapedText} done`); - - return factory.updateClassDeclaration( - classDeclaration, - classDeclaration.decorators, - classDeclaration.modifiers, - classDeclaration.name, - classDeclaration.typeParameters, - classDeclaration.heritageClauses, - newMembers - ); -} \ No newline at end of file diff --git a/src.compiler/TranspilerBase.ts b/src.compiler/TranspilerBase.ts new file mode 100644 index 000000000..afaab9ad1 --- /dev/null +++ b/src.compiler/TranspilerBase.ts @@ -0,0 +1,40 @@ +import * as ts from 'typescript'; + +export default function (emit: (program: ts.Program) => void) { + function createDiagnosticReporter(pretty?: boolean): ts.DiagnosticReporter { + const host: ts.FormatDiagnosticsHost = { + getCurrentDirectory: () => ts.sys.getCurrentDirectory(), + getNewLine: () => ts.sys.newLine, + getCanonicalFileName: ts.sys.useCaseSensitiveFileNames + ? x => x + : x => x.toLowerCase(), + }; + + if (!pretty) { + return diagnostic => ts.sys.write(ts.formatDiagnostic(diagnostic, host)); + } + + return diagnostic => { + ts.sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine()); + }; + } + + const commandLine = ts.parseCommandLine(ts.sys.args); + if (!ts.sys.fileExists(commandLine.options.project!)) { + ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); + } + + const parseConfigFileHost: ts.ParseConfigFileHost = ts.sys; + + const parsedCommandLine = ts.getParsedCommandLineOfConfigFile(commandLine.options.project!, commandLine.options, parseConfigFileHost, /*extendedConfigCache*/ undefined, commandLine.watchOptions)!; + const program = ts.createProgram({ + rootNames: parsedCommandLine.fileNames, + options: parsedCommandLine.options, + projectReferences: parsedCommandLine.projectReferences, + host: ts.createCompilerHost(parsedCommandLine.options), + }); + + program.getTypeChecker(); + + emit(program); +} \ No newline at end of file diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index 0b130b349..c5fd35ecb 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -1145,7 +1145,12 @@ export default class CSharpAstTransformer { classElement: ts.MethodDeclaration ) { const signature = this._context.typeChecker.getSignatureFromDeclaration(classElement); - const returnType = this._context.typeChecker.getReturnTypeOfSignature(signature!); + if (!signature) { + console.log('no signature'); + } + const returnType: ts.Type | undefined = signature + ? this._context.typeChecker.getReturnTypeOfSignature(signature) + : undefined; const csMethod: cs.MethodDeclaration = { parent: parent, @@ -1350,7 +1355,7 @@ export default class CSharpAstTransformer { nodeType: cs.SyntaxKind.VariableDeclaration, parent: parent, tsNode: s, - name: s.name.getText(), + name: (s.name as ts.Identifier).text, type: {} as cs.TypeNode } as cs.VariableDeclaration; @@ -1798,7 +1803,7 @@ export default class CSharpAstTransformer { const csParameter: cs.ParameterDeclaration = { nodeType: cs.SyntaxKind.ParameterDeclaration, - name: p.name.getText(), + name: (p.name as ts.Identifier).text, parent: csMethod, type: this.createUnresolvedTypeNode(null, p.type ?? p, type), tsNode: p, diff --git a/src.compiler/csharp/CSharpEmitter.ts b/src.compiler/csharp/CSharpEmitter.ts index a890bd7bb..9a64ce1c2 100644 --- a/src.compiler/csharp/CSharpEmitter.ts +++ b/src.compiler/csharp/CSharpEmitter.ts @@ -7,9 +7,7 @@ export default function emit(program: ts.Program): ts.Diagnostic[] { const diagnostics: ts.Diagnostic[] = []; const context = new CSharpEmitterContext(program); - - program.getRootFileNames().forEach(file => { - const sourceFile = program.getSourceFile(file)!; + sourceFiles.forEach(sourceFile => { const transformer = new CSharpAstTransformer(sourceFile, context); transformer.transform(); }); diff --git a/src.compiler/csharp/CSharpEmitterContext.ts b/src.compiler/csharp/CSharpEmitterContext.ts index 8cf1055e1..453bf2bf3 100644 --- a/src.compiler/csharp/CSharpEmitterContext.ts +++ b/src.compiler/csharp/CSharpEmitterContext.ts @@ -809,7 +809,11 @@ export default class CSharpEmitterContext { } public isBooleanSmartCast(tsNode: ts.Node) { - let tsParent = tsNode.parent!; + let tsParent = tsNode.parent; + if(!tsParent) { + return false; + } + while (tsParent.kind === ts.SyntaxKind.ParenthesizedExpression) { tsNode = tsParent; tsParent = tsParent.parent!; diff --git a/src.compiler/csharp/CSharpTranspiler.ts b/src.compiler/csharp/CSharpTranspiler.ts index 4a7f53c11..378259efd 100644 --- a/src.compiler/csharp/CSharpTranspiler.ts +++ b/src.compiler/csharp/CSharpTranspiler.ts @@ -1,87 +1,4 @@ -import * as ts from 'typescript'; import emit from './CSharpEmitter'; +import transpiler from '../TranspilerBase' -function createDiagnosticReporter(pretty?: boolean): ts.DiagnosticReporter { - const host: ts.FormatDiagnosticsHost = { - getCurrentDirectory: () => ts.sys.getCurrentDirectory(), - getNewLine: () => ts.sys.newLine, - getCanonicalFileName: ts.sys.useCaseSensitiveFileNames - ? x => x - : x => x.toLowerCase(), - }; - - if (!pretty) { - return diagnostic => ts.sys.write(ts.formatDiagnostic(diagnostic, host)); - } - - return diagnostic => { - ts.sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine()); - }; -} - -const commandLine = ts.parseCommandLine(ts.sys.args); -if (!ts.sys.fileExists(commandLine.options.project!)) { - ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); -} - -let reportDiagnostic = createDiagnosticReporter(); - -const parseConfigFileHost: ts.ParseConfigFileHost = ts.sys; -parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = diagnostic => { - reportDiagnostic(diagnostic); - ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); -}; - -const parsedCommandLine = ts.getParsedCommandLineOfConfigFile(commandLine.options.project!, commandLine.options, parseConfigFileHost, /*extendedConfigCache*/ undefined, commandLine.watchOptions)!; -const pretty = !!ts.sys.writeOutputIsTTY && ts.sys.writeOutputIsTTY(); -if (pretty) { - reportDiagnostic = createDiagnosticReporter(true); -} - -const program = ts.createProgram({ - rootNames: parsedCommandLine.fileNames, - options: parsedCommandLine.options, - projectReferences: parsedCommandLine.projectReferences, - host: ts.createCompilerHost(parsedCommandLine.options), -}); - -const allDiagnostics = program.getConfigFileParsingDiagnostics().slice(); -const configFileParsingDiagnosticsLength = allDiagnostics.length; -allDiagnostics.push(...program.getSyntacticDiagnostics()); - -if (allDiagnostics.length === configFileParsingDiagnosticsLength) { - allDiagnostics.push(...program.getOptionsDiagnostics()); - allDiagnostics.push(...program.getGlobalDiagnostics()); - allDiagnostics.push(...program.getSemanticDiagnostics()); -} - -const emitDiagnostics = emit(program); -allDiagnostics.push(...emitDiagnostics); - -let diagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); -let errorCount = 0; -let warningCount = 0; -diagnostics.forEach(d => { - switch (d.category) { - case ts.DiagnosticCategory.Error: errorCount++; break; - case ts.DiagnosticCategory.Warning: warningCount++; break; - } - reportDiagnostic(d); -}); - -if (pretty) { - reportDiagnostic({ - file: undefined, - start: undefined, - length: undefined, - code: 6194, - messageText:`Compilation completed with ${errorCount} errors and ${warningCount} warnings${ts.sys.newLine}`, - category: errorCount > 0 ? ts.DiagnosticCategory.Error : warningCount > 0 ? ts.DiagnosticCategory.Warning : ts.DiagnosticCategory.Message, - }); -} - -if (errorCount > 0) { - ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsGenerated); -} else { - ts.sys.exit(ts.ExitStatus.Success); -} \ No newline at end of file +transpiler(emit); \ No newline at end of file diff --git a/src.compiler/typescript/AlphaTabGenerator.ts b/src.compiler/typescript/AlphaTabGenerator.ts new file mode 100644 index 000000000..489cc1ae8 --- /dev/null +++ b/src.compiler/typescript/AlphaTabGenerator.ts @@ -0,0 +1,9 @@ +import * as ts from 'typescript'; +import cloneEmit from './CloneEmitter'; +import serializerEmit from './SerializerEmitter'; +import transpiler from '../TranspilerBase' + +transpiler(cloneEmit); +transpiler(serializerEmit); + +ts.sys.exit(ts.ExitStatus.Success); \ No newline at end of file diff --git a/src.compiler/typescript/CloneEmitter.ts b/src.compiler/typescript/CloneEmitter.ts new file mode 100644 index 000000000..343212181 --- /dev/null +++ b/src.compiler/typescript/CloneEmitter.ts @@ -0,0 +1,362 @@ +/** + * This file contains an emitter which generates classes to clone + * any data models following certain rules. + */ +import * as path from 'path'; +import * as ts from 'typescript'; +import createEmitter from './EmitterBase' +import { addNewLines } from '../BuilderHelpers'; +import { getTypeWithNullableInfo } from '../BuilderHelpers'; +import { unwrapArrayItemType } from '../BuilderHelpers'; + +function removeExtension(fileName: string) { + return fileName.substring(0, fileName.lastIndexOf('.')); +} + +function toImportPath(fileName: string) { + return "@" + removeExtension(fileName).split('\\').join('/'); +} + +function isClonable(type: ts.Type): boolean { + if (!type.symbol) { + return false; + } + + const declaration = type.symbol.valueDeclaration; + if (declaration) { + return !!ts.getJSDocTags(declaration).find(t => t.tagName.text === 'cloneable'); + } + + return false; +} + +function isCloneMember(propertyDeclaration: ts.PropertyDeclaration) { + if (propertyDeclaration.modifiers) { + if (propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword || m.kind === ts.SyntaxKind.ReadonlyKeyword)) { + return false; + } + + if (!propertyDeclaration.modifiers.find(m => m.kind === ts.SyntaxKind.PublicKeyword)) { + return false; + } + } + + if (ts.getJSDocTags(propertyDeclaration).find(t => t.tagName.text === 'clone_ignore')) { + return false; + } + + return true; +} + +function generateClonePropertyStatements(prop: ts.PropertyDeclaration, typeChecker: ts.TypeChecker, + importer: (name: string, module: string) => void): ts.Statement[] { + const propertyType = getTypeWithNullableInfo(typeChecker, prop.type!); + + const statements: ts.Statement[] = []; + + const propertyName = (prop.name as ts.Identifier).text; + + function assign(expr: ts.Expression) { + return [ts.factory.createExpressionStatement( + ts.factory.createAssignment( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('clone'), + propertyName + ), + expr + ) + )]; + } + + const arrayItemType = unwrapArrayItemType(propertyType.type!, typeChecker); + if (arrayItemType) { + if (isClonable(arrayItemType)) { + const collectionAddMethod = ts.getJSDocTags(prop) + .filter(t => t.tagName.text === 'clone_add') + .map(t => t.comment ?? "")[0]; + + importer(arrayItemType.symbol!.name + "Cloner", './' + arrayItemType.symbol!.name + "Cloner"); + const loopItems = [ + ...assign(ts.factory.createArrayLiteralExpression(undefined)), + + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration('i')], + ts.NodeFlags.Const + ), + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ), + ts.factory.createBlock([ + ts.factory.createExpressionStatement( + collectionAddMethod + // clone.addProp(ItemTypeCloner.clone(i)) + ? ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('clone'), + collectionAddMethod + ), + undefined, + [ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(arrayItemType.symbol!.name + "Cloner"), + 'clone' + ), + undefined, + [ + ts.factory.createIdentifier('i') + ] + )] + ) + // clone.prop.push(ItemTypeCloner.clone(i)) + : ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('clone'), + propertyName + ), + 'push' + ), + undefined, + [ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(arrayItemType.symbol!.name + "Cloner"), + 'clone' + ), + undefined, + [ + ts.factory.createIdentifier('i') + ] + )] + ) + ) + ]) + )]; + + if (propertyType.isNullable) { + // if(original.prop) { + // clone.prop = []; + // for(const i of original.prop) { clone.addProp(ItemTypeCloner.clone(i)); } + // // or + // for(const i of original.prop) { clone.prop.add(ItemTypeCloner.clone(i)); } + // } + statements.push( + ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ), + ts.factory.createBlock( + loopItems + ), + undefined + ) + ) + } else { + // clone.prop = []; + // for(const i of original.prop) { clone.addProp(ItemTypeCloner.clone(i)); } + // // or + // for(const i of original.prop) { clone.prop.add(ItemTypeCloner.clone(i)); } + statements.push(...loopItems); + } + } else { + const sliceCall = + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ), + 'slice' + ), + undefined, + [] + ); + + if (propertyType.isNullable) { + statements.push(...assign( + ts.factory.createConditionalExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + sliceCall, + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + )); + } else { + // clone.prop = original.prop.splice() + statements.push(...assign(sliceCall)); + } + } + } else { + if (isClonable(propertyType.type!)) { + importer(propertyType.type.symbol!.name + "Cloner", './' + propertyType.type.symbol!.name + "Cloner"); + + // clone.prop = original.prop ? TypeNameCloner.clone(original.prop) : null + statements.push(...assign( + ts.factory.createConditionalExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(propertyType.type.symbol!.name + "Cloner"), + 'clone' + ), + undefined, + [ + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ) + ] + ), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + )); + } else { + // clone.prop = original.prop + statements.push(...assign( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('original'), + propertyName + ) + )); + } + } + + return statements; +} + +function generateCloneBody(program: ts.Program, input: ts.ClassDeclaration, importer: (name: string, module: string) => void): ts.Block { + const typeChecker = program.getTypeChecker(); + const propertiesToSerialize = input.members.filter( + m => ts.isPropertyDeclaration(m) && isCloneMember(m) + ).map(m => m as ts.PropertyDeclaration); + + const bodyStatements = propertiesToSerialize.reduce((stmts, prop) => { + stmts.push(...generateClonePropertyStatements(prop, typeChecker, importer)); + return stmts; + }, new Array()); + + return ts.factory.createBlock(addNewLines([ + // const clone = new Type(); + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration( + 'clone', + undefined, + undefined, + ts.factory.createNewExpression( + ts.factory.createIdentifier(input.name!.text), + undefined, + [] + ) + ) + ], ts.NodeFlags.Const) + ), + ...bodyStatements, + // return json; + ts.factory.createReturnStatement(ts.factory.createIdentifier('clone')) + ])); +} + + +function createCloneMethod(program: ts.Program, input: ts.ClassDeclaration, importer: (name: string, module: string) => void) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), + ], + undefined, + 'clone', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'original', + undefined, + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + undefined + ) + ], + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + generateCloneBody(program, input, importer) + ) +} + +export default createEmitter('cloneable', (program, input) => { + console.log(`Writing Cloner for ${input.name!.text}`); + const sourceFileName = path.relative( + path.join(path.resolve(program.getCompilerOptions().baseUrl!)), + path.resolve(input.getSourceFile().fileName) + ); + + const statements: ts.Statement[] = []; + + function importer(name: string, module: string) { + statements.push(ts.factory.createImportDeclaration( + undefined, + undefined, + ts.factory.createImportClause( + false, + undefined, + ts.factory.createNamedImports([ts.factory.createImportSpecifier( + undefined, + ts.factory.createIdentifier(name) + )]) + ), + ts.factory.createStringLiteral(module) + )) + } + + statements.push(ts.factory.createClassDeclaration( + [], + [ + ts.factory.createModifier(ts.SyntaxKind.ExportKeyword), + ], + input.name!.text + 'Cloner', + undefined, + undefined, + [ + createCloneMethod(program, input, importer) + ] + )); + + const sourceFile = ts.factory.createSourceFile([ + ts.factory.createImportDeclaration( + undefined, + undefined, + ts.factory.createImportClause(false, + undefined, + ts.factory.createNamedImports([ts.factory.createImportSpecifier( + undefined, + ts.factory.createIdentifier(input.name!.text) + )]) + ), + ts.factory.createStringLiteral(toImportPath(sourceFileName)) + ), + ...statements + ], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None); + + return sourceFile; +}); \ No newline at end of file diff --git a/src.compiler/typescript/EmitterBase.ts b/src.compiler/typescript/EmitterBase.ts new file mode 100644 index 000000000..7f7316368 --- /dev/null +++ b/src.compiler/typescript/EmitterBase.ts @@ -0,0 +1,101 @@ +import * as path from 'path'; +import * as ts from 'typescript'; +import * as fs from 'fs'; + +export default function createEmitter(jsDocMarker: string, generate: (program: ts.Program, classDeclaration: ts.ClassDeclaration) => ts.SourceFile) { + + function generateClass(program: ts.Program, classDeclaration: ts.ClassDeclaration) { + const sourceFileName = path.relative( + path.resolve(program.getCompilerOptions().baseUrl!, 'src'), + path.resolve(classDeclaration.getSourceFile().fileName) + ); + + const result = generate(program, classDeclaration); + const defaultClass = result.statements.filter(stmt => ts.isClassDeclaration(stmt) && + stmt.modifiers!.find(m => m.kind === ts.SyntaxKind.ExportKeyword) + )[0] as ts.ClassDeclaration; + + const targetFileName = path.join( + path.resolve(program.getCompilerOptions().baseUrl!), + 'src/generated', + path.dirname(sourceFileName), + defaultClass.name!.text + '.ts' + ); + + fs.mkdirSync(path.dirname(targetFileName), { recursive: true }); + + const fileHandle = fs.openSync(targetFileName, 'w'); + + fs.writeSync(fileHandle, '// \n'); + fs.writeSync(fileHandle, '// This code was auto-generated.\n'); + fs.writeSync(fileHandle, '// Changes to this file may cause incorrect behavior and will be lost if\n'); + fs.writeSync(fileHandle, '// the code is regenerated.\n'); + fs.writeSync(fileHandle, '// \n'); + + const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); + const source = printer.printNode(ts.EmitHint.Unspecified, result, result); + const servicesHost: ts.LanguageServiceHost = { + getScriptFileNames: () => [targetFileName], + getScriptVersion: fileName => result.languageVersion.toString(), + getScriptSnapshot: fileName => { + if (fileName != targetFileName) { + return undefined; + } + + return ts.ScriptSnapshot.fromString(source); + }, + getCurrentDirectory: () => process.cwd(), + getCompilationSettings: () => program.getCompilerOptions(), + getDefaultLibFileName: options => ts.getDefaultLibFilePath(options), + fileExists: fileName => fileName === targetFileName, + readFile: fileName => fileName === targetFileName ? source : "", + readDirectory: ts.sys.readDirectory, + directoryExists: ts.sys.directoryExists, + getDirectories: ts.sys.getDirectories, + }; + + const languageService = ts.createLanguageService(servicesHost, ts.createDocumentRegistry()); + const textChanges: ts.TextChange[] = languageService.getFormattingEditsForDocument(targetFileName, { + convertTabsToSpaces: true, + insertSpaceAfterCommaDelimiter: true, + insertSpaceAfterKeywordsInControlFlowStatements: true, + insertSpaceBeforeAndAfterBinaryOperators: true, + newLineCharacter: "\n", + indentStyle: ts.IndentStyle.Smart, + indentSize: 4, + tabSize: 4, + }); + textChanges.sort((a, b) => b.span.start - a.span.start); + + let finalText = source; + for (const textChange of textChanges) { + const { span } = textChange; + finalText = finalText.slice(0, span.start) + textChange.newText + + finalText.slice(span.start + span.length); + } + + finalText = finalText.replace(/\/\/ */g, ''); + + fs.writeSync(fileHandle, finalText); + fs.writeSync(fileHandle, '\n'); + + fs.closeSync(fileHandle); + } + + function scanSourceFile(program: ts.Program, sourceFile: ts.SourceFile) { + sourceFile.statements.forEach(stmt => { + if (ts.isClassDeclaration(stmt)) { + const isActive = ts.getJSDocTags(stmt).find(t => t.tagName.text === jsDocMarker); + if (isActive) { + generateClass(program, stmt); + } + } + }); + } + + return function emit(program: ts.Program) { + program.getRootFileNames().forEach(file => { + scanSourceFile(program, program.getSourceFile(file)!); + }); + } +} \ No newline at end of file diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts new file mode 100644 index 000000000..2c3c505bd --- /dev/null +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -0,0 +1,1174 @@ +/** + * This file contains an emitter which generates classes to serialize + * any data models to and from JSON following certain rules. + */ + +import * as path from 'path'; +import * as ts from 'typescript'; +import createEmitter from './EmitterBase' +import { addNewLines } from '../BuilderHelpers'; +import { isPrimitiveType } from '../BuilderHelpers'; +import { getTypeWithNullableInfo } from '../BuilderHelpers'; +import { isTypedArray } from '../BuilderHelpers'; +import { unwrapArrayItemType } from '../BuilderHelpers'; +import { isMap } from '../BuilderHelpers'; +import { isEnumType } from '../BuilderHelpers'; +import { isNumberType } from '../BuilderHelpers'; +import { wrapToNonNull } from '../BuilderHelpers'; + +interface JsonProperty { + property: ts.PropertyDeclaration; + jsonNames: string[]; +} + +function isImmutable(type: ts.Type | null): boolean { + if (!type || !type.symbol) { + return false; + } + + const declaration = type.symbol.valueDeclaration; + if (declaration) { + return !!ts.getJSDocTags(declaration).find(t => t.tagName.text === 'json_immutable'); + } + + return false; +} + +function removeExtension(fileName: string) { + return fileName.substring(0, fileName.lastIndexOf('.')); +} + +function toImportPath(fileName: string) { + return "@" + removeExtension(fileName).split('\\').join('/'); +} + +function findModule(type: ts.Type, options: ts.CompilerOptions) { + if (type.symbol) { + for (const decl of type.symbol.declarations) { + const file = decl.getSourceFile(); + if (file) { + const relative = path.relative( + path.join(path.resolve(options.baseUrl!)), + path.resolve(file.fileName) + ); + return toImportPath(relative); + } + } + + return './' + type.symbol.name; + } + + return ''; +} + +function findSerializerModule(type: ts.Type, options: ts.CompilerOptions) { + let module = findModule(type, options); + const importPath = module.split('/'); + importPath.splice(1, 0, 'generated'); + return importPath.join('/') + 'Serializer'; +} + +// +// FromJson +function generateFromJsonBody(input: ts.ClassDeclaration) { + const statements: ts.Statement[] = []; + // const obj = new Type(); + statements.push( + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration( + 'obj', + undefined, + undefined, + ts.factory.createNewExpression(ts.factory.createIdentifier(input.name!.text), [], []) + ) + ], ts.NodeFlags.Const) + ) + ); + + // this.fillFromJson(obj, json); + statements.push( + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'fillFromJson'), + [], + [ + ts.factory.createIdentifier('obj'), + ts.factory.createIdentifier('json'), + ] + ) + ) + ); + + // return obj; + statements.push( + // return json; + ts.factory.createReturnStatement(ts.factory.createIdentifier('obj')) + ); + + return ts.factory.createBlock(addNewLines(statements)); +} + +function createFromJsonMethod(input: ts.ClassDeclaration) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), + ], + undefined, + 'fromJson', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'json', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + undefined + ) + ], + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + generateFromJsonBody(input) + ); +} + +// +// fillFromJson +function generateFillFromJsonBody() { + return ts.factory.createBlock(addNewLines([ + ts.factory.createIfStatement( + // if(json) for($k in json) { this.setProperty(obj, $k.toLowerCase(), json[$k]) } + ts.factory.createIdentifier('json'), + ts.factory.createBlock([ + ts.factory.createForInStatement( + ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('$k')], ts.NodeFlags.Const), + ts.factory.createIdentifier('json'), + ts.factory.createBlock([ + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'setProperty'), + [], + [ + // obj + ts.factory.createIdentifier('obj'), + // $k.toLowerCase(), + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$k'), 'toLowerCase'), [], []), + // json[$k] + ts.factory.createElementAccessExpression(ts.factory.createIdentifier('json'), ts.factory.createIdentifier('$k')) + ] + ) + ) + ]) + ) + ]) + ) + ])); +} + +function createFillFromJsonMethod(input: ts.ClassDeclaration) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) + ], + undefined, + 'fillFromJson', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'obj', + undefined, + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'json', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ) + ], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + generateFillFromJsonBody() + ) +} + +// +// toJson +function generateToJsonBody() { + return ts.factory.createBlock(addNewLines([ + // if(!obj) { return null; } + ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createIdentifier('obj') + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement(ts.factory.createNull()) + ]) + ), + + // const json:any = {}; + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration( + 'json', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + ts.factory.createObjectLiteralExpression() + ) + ], ts.NodeFlags.Const) + ), + + // this.fillToJson(obj, json) + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'fillToJson'), + [], + [ + ts.factory.createIdentifier('obj'), + ts.factory.createIdentifier('json') + ] + ) + ), + + // return json; + ts.factory.createReturnStatement(ts.factory.createIdentifier('json')) + ])); +} + +function createToJsonMethod(input: ts.ClassDeclaration) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), + ], + undefined, + 'toJson', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'obj', + undefined, + ts.factory.createUnionTypeNode([ + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]), + undefined + ) + ], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), + generateToJsonBody() + ); +} + +// +// fillToJson +function generateFillToJsonBody( + program: ts.Program, + propertiesToSerialize: JsonProperty[], + importer: (name: string, module: string) => void) { + + const statements: ts.Statement[] = []; + + for (let prop of propertiesToSerialize) { + const fieldName = (prop.property.name as ts.Identifier).text; + const jsonName = prop.jsonNames.filter(n => n !== '')[0]; + + const accessJsonName = function (): ts.Expression { + return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('json'), jsonName); + }; + const accessField = function (): ts.Expression { + return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)); + }; + + const assignToJsonName = function (value: ts.Expression): ts.Statement { + return ts.factory.createExpressionStatement(ts.factory.createAssignment(accessJsonName(), value)); + }; + + if (jsonName) { + const typeChecker = program.getTypeChecker(); + const type = getTypeWithNullableInfo(typeChecker, prop.property.type!); + if (isPrimitiveType(type.type!)) { + // json.jsonName = obj.fieldName + statements.push(assignToJsonName(accessField())); + } else if (isTypedArray(type.type!)) { + const arrayItemType = unwrapArrayItemType(type.type!, typeChecker); + if (!arrayItemType || isPrimitiveType(arrayItemType)) { + // json.jsonName = obj.fieldName ? obj.fieldName.slice() : null + if (type.isNullable) { + statements.push( + assignToJsonName( + ts.factory.createConditionalExpression( + accessField(), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + ) + ); + } else { + statements.push( + assignToJsonName(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) + ); + } + } else { + // json.jsonName = obj.fieldName ? obj.fieldName.map($li => TypeNameSerializer.toJson($li)) : null + let itemSerializer = arrayItemType.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); + + const mapCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'map'), undefined, [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$li')], + undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + undefined, + [ts.factory.createIdentifier('$li')] + ) + ), + ]); + if (type.isNullable) { + statements.push( + assignToJsonName( + ts.factory.createConditionalExpression( + accessField(), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + mapCall, + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + ) + ); + } else { + statements.push( + assignToJsonName(mapCall) + ); + } + } + } else if (isMap(type.type)) { + const mapType = type.type as ts.TypeReference; + if (!isPrimitiveType(mapType.typeArguments![0])) { + throw new Error('only Map maps are supported extend if needed!'); + } + // json.jsonName = { } as any; + // this.fieldName.forEach((val, key) => (json.jsonName as any)[key] = val)) + statements.push( + assignToJsonName( + ts.factory.createAsExpression( + ts.factory.createObjectLiteralExpression(), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ) + ) + ); + + // json.jsonName = obj.fieldName ? obj.fieldName.map($li => TypeNameSerializer.toJson($li)) : null + let itemSerializer: string = ''; + if (!isPrimitiveType(mapType.typeArguments![1])) { + itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); + } + + const mapValue = isPrimitiveType(mapType.typeArguments![1]) + ? ts.factory.createIdentifier('$mv') + : ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + undefined, + [ts.factory.createIdentifier('$mv')] + ); + + statements.push( + ts.factory.createExpressionStatement( + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'forEach'), undefined, [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$mv'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$mk') + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock([ + ts.factory.createExpressionStatement( + ts.factory.createAssignment( + ts.factory.createElementAccessExpression( + ts.factory.createAsExpression( + accessJsonName(), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ), + ts.factory.createIdentifier('$mk') + ), + mapValue + ) + ) + ]) + ) + ]) + ) + ); + } else if (isImmutable(type.type)) { + let itemSerializer = type.type.symbol.name; + importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); + + // json.jsonName = TypeName.toJson(this.fieldName); + statements.push( + assignToJsonName( + wrapToNonNull( + type.isNullable, + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + [], + [accessField()] + ), + ts.factory + ) + ) + ); + } else { + // not nullable: + // if(json.jsonName) { + // FieldSerializer.fillToJson(obj.fieldName, json.jsonName) + // } else { + // json.jsonName = FieldSerializer.toJson(obj.fieldName)!; + // } + + // nullable: + // if(json.jsonName) { + // if(obj.fieldName) FieldSerializer.fillToJson(obj.fieldName, json.jsonName) + // } else { + // json.jsonName = FieldSerializer.toJson(obj.fieldName); + // } + + let itemSerializer = type.type.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); + + // this.field.fillToJson(json.jsonName) + let fillToJsonStatent: ts.Statement = ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fillToJson'), + [], + [ + accessField(), + accessJsonName() + ] + ) + ); + if (type.isNullable) { + fillToJsonStatent = ts.factory.createIfStatement(accessField(), ts.factory.createBlock([fillToJsonStatent])); + } + + statements.push( + ts.factory.createIfStatement( + // if(json.jsonName) + accessJsonName(), + // TypeSerializer.fillToJson(obj.fieldName, json.jsonName) + ts.factory.createBlock([fillToJsonStatent]), + // else json.jsonName = ... + ts.factory.createBlock([ + assignToJsonName( + wrapToNonNull( + type.isNullable, + ts.factory.createCallExpression( + // TypeName.toJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + [], + [accessField()] + ), + ts.factory + ), + ) + ]) + ) + ); + } + } + } + + return ts.factory.createBlock(addNewLines(statements)) +} + +function createFillToJsonMethod(program: ts.Program, + input: ts.ClassDeclaration, + propertiesToSerialize: JsonProperty[], + importer: (name: string, module: string) => void +) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) + ], + undefined, + 'fillToJson', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'obj', + undefined, + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'json', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ) + ], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + generateFillToJsonBody(program, propertiesToSerialize, importer) + ) +} + +// +// setProperty +function createEnumMapping(value: string, type: ts.Type): ts.Expression { + // isNan(parseInt(value)) ? Enum[Object.keys(Enum).find($k => $k.toLowerCase() === value.toLowerCase()] : parseInt(value) + return ts.factory.createConditionalExpression( + ts.factory.createCallExpression(ts.factory.createIdentifier('isNaN'), undefined, [ + ts.factory.createCallExpression(ts.factory.createIdentifier('parseInt'), undefined, [ts.factory.createIdentifier(value)]) + ]), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createElementAccessExpression( + ts.factory.createIdentifier(type.symbol.name), + ts.factory.createAsExpression( + ts.factory.createCallExpression( + // Object.keys(EnumName).find + ts.factory.createPropertyAccessExpression( + // Object.keys(EnumName) + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), 'keys'), + [], + [ts.factory.createIdentifier(type.symbol.name)] + ), + 'find' + ), + [], + [ + ts.factory.createArrowFunction( + [], + [], + [ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$k')], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBinaryExpression( + ts.factory.createCallExpression( + // $.toLowerCase() + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$k'), 'toLowerCase'), + [], + [] + ), + // === + ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), + // value.toLowerCase() + ts.factory.createCallExpression( + // $.toLowerCase() + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(value), 'toLowerCase'), + [], + [] + ) + ) + ) + ] + ), + ts.factory.createTypeOperatorNode( + ts.SyntaxKind.KeyOfKeyword, + ts.factory.createTypeQueryNode(ts.factory.createIdentifier(type.symbol.name)) + ) + ) + ), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createCallExpression(ts.factory.createIdentifier('parseInt'), undefined, [ts.factory.createIdentifier(value)]) + ); +} + +function generateSetPropertyBody(program: ts.Program, + propertiesToSerialize: JsonProperty[], + importer: (name: string, module: string) => void +) { + const statements: ts.Statement[] = []; + const cases: ts.CaseOrDefaultClause[] = []; + + const typeChecker = program.getTypeChecker(); + for (const prop of propertiesToSerialize) { + const jsonNames = prop.jsonNames.map(j => j.toLowerCase()); + const caseValues: string[] = jsonNames.filter(j => j !== ''); + const fieldName = (prop.property.name as ts.Identifier).text; + + const caseStatements: ts.Statement[] = []; + + const type = getTypeWithNullableInfo(typeChecker, prop.property.type); + + const assignField = function (expr: ts.Expression): ts.Statement { + return ts.factory.createExpressionStatement( + ts.factory.createAssignment(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), expr) + ); + }; + + if (isEnumType(type.type)) { + // obj.fieldName = enummapping + // return true; + importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())) + if (type.isNullable) { + caseStatements.push(assignField( + ts.factory.createConditionalExpression( + ts.factory.createBinaryExpression( + ts.factory.createIdentifier('value'), + ts.SyntaxKind.EqualsEqualsEqualsToken, + ts.factory.createNull() + ), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createNull(), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + createEnumMapping('value', type.type) + ) + )); + } else { + caseStatements.push(assignField(createEnumMapping('value', type.type))); + } + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } else if (isPrimitiveType(type.type)) { + // obj.fieldName = value + // return true; + caseStatements.push(assignField(ts.factory.createIdentifier('value'))); + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } else if (isTypedArray(type.type!)) { + const arrayItemType = unwrapArrayItemType(type.type!, typeChecker); + if (!arrayItemType || isPrimitiveType(arrayItemType)) { + // nullable: + // obj.fieldName = value ? value.slice() : null + // return true; + + // not nullable: + // obj.fieldName = value.slice() + // return true; + const sliceCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('value'), 'slice'), [], []); + if (type.isNullable) { + caseStatements.push( + assignField( + ts.factory.createConditionalExpression( + ts.factory.createIdentifier('value'), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + sliceCall, + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + ) + ); + } else { + caseStatements.push( + assignField(sliceCall) + ); + } + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } else { + const collectionAddMethod = ts.getJSDocTags(prop.property) + .filter(t => t.tagName.text === 'json_add') + .map(t => t.comment ?? "")[0]; + + // obj.fieldName = []; + // for(const $li of value) { + // obj.addFieldName(Type.FromJson($li)); + // } + // or + // for(const $li of value) { + // obj.fieldName.push(Type.FromJson($li)); + // } + + let itemSerializer = arrayItemType.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); + + const itemFromJson = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ts.factory.createIdentifier('$li')] + ); + + const loopItems = [ + assignField(ts.factory.createArrayLiteralExpression(undefined)), + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration('$li')], + ts.NodeFlags.Const + ), + ts.factory.createIdentifier('value'), + ts.factory.createExpressionStatement( + collectionAddMethod + // obj.addFieldName(ItemTypeSerializer.FromJson($li)) + ? ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('obj'), + collectionAddMethod + ), + undefined, + [itemFromJson] + ) + // obj.fieldName.push(ItemTypeSerializer.FromJson($li)) + : ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('obj'), + fieldName + ), + 'push' + ), + undefined, + [itemFromJson] + ) + ) + )]; + + if (type.isNullable) { + caseStatements.push(ts.factory.createIfStatement( + ts.factory.createIdentifier('value'), + ts.factory.createBlock(loopItems) + )); + } else { + caseStatements.push(...loopItems); + } + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } + + } else if (isMap(type.type)) { + // this.fieldName = new Map(); + // for(let key in value) { + // if(value.hasOwnProperty(key) obj.fieldName.set(, value[key]); + // } + // or + // for(let key in value) { + // if(value.hasOwnProperty(key) obj.addFieldName(, value[key]); + // } + // return true; + + const mapType = type.type as ts.TypeReference; + if (!isPrimitiveType(mapType.typeArguments![0])) { + throw new Error('only Map maps are supported extend if needed!'); + } + + const mapKey = isEnumType(mapType.typeArguments![0]) + ? createEnumMapping('$mk', mapType.typeArguments![0]) + : isNumberType(mapType.typeArguments![0]) + ? ts.factory.createCallExpression( + ts.factory.createIdentifier('parseInt'), + undefined, + [ts.factory.createIdentifier('$mk')] + ) + : ts.factory.createIdentifier('$mk'); + + if (isEnumType(mapType.typeArguments![0])) { + importer(mapType.typeArguments![0].symbol!.name, findModule(mapType.typeArguments![0], program.getCompilerOptions())); + } + + let mapValue: ts.Expression = ts.factory.createElementAccessExpression(ts.factory.createIdentifier('value'), ts.factory.createIdentifier('$mk')); + let itemSerializer: string = ''; + if (!isPrimitiveType(mapType.typeArguments![1])) { + itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); + importer(mapType.typeArguments![1]!.symbol.name, findModule(mapType.typeArguments![1], program.getCompilerOptions())); + mapValue = ts.factory.createCallExpression( + // TypeName.fromJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [mapValue] + ); + } + + const collectionAddMethod = ts.getJSDocTags(prop.property) + .filter(t => t.tagName.text === 'json_add') + .map(t => t.comment ?? "")[0]; + + caseStatements.push(assignField(ts.factory.createNewExpression(ts.factory.createIdentifier('Map'), [ + typeChecker.typeToTypeNode(mapType.typeArguments![0], undefined, undefined)!, + typeChecker.typeToTypeNode(mapType.typeArguments![1], undefined, undefined)!, + ], []))); + caseStatements.push( + ts.factory.createForInStatement( + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration(ts.factory.createIdentifier('$mk'), undefined, undefined)], + ts.NodeFlags.Let + ), + ts.factory.createIdentifier('value'), + ts.factory.createIfStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('value'), 'hasOwnProperty'), + undefined, + [ts.factory.createIdentifier('$mk')] + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + collectionAddMethod + ? ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), collectionAddMethod) + : ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)), + ts.factory.createIdentifier('set') + ), + undefined, + [ + mapKey, + mapValue + ] + ) + ) + ) + ) + ); + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } else if (isImmutable(type.type)) { + let itemSerializer = type.type.symbol.name; + importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); + + // obj.fieldName = TypeName.fromJson(value)! + // return true; + caseStatements.push( + assignField( + wrapToNonNull( + type.isNullable, + ts.factory.createCallExpression( + // TypeName.fromJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ts.factory.createIdentifier('value')] + ), + ts.factory + ) + ) + ); + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + } else { + // for complex types it is a bit more tricky + // if the property matches exactly, we use fromJson + // if the property starts with the field name, we try to set a sub-property + const jsonNameArray = ts.factory.createArrayLiteralExpression(jsonNames.map(n => ts.factory.createStringLiteral(n))); + + let itemSerializer = type.type.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); + importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())); + + statements.push( + ts.factory.createIfStatement( + // if(["", "core"].indexOf(property) >= 0) + ts.factory.createBinaryExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(jsonNameArray, 'indexOf'), + [], + [ts.factory.createIdentifier('property')] + ), + ts.SyntaxKind.GreaterThanEqualsToken, + ts.factory.createNumericLiteral('0') + ), + ts.factory.createBlock([ + // if(obj.field) { + // TypeNameSerializer.fillFromJson(obj.field, value); + // } else { + // obj.field = TypeNameSerializer.fromJson(value); + // or + // obj.field = value ? TypeNameSerializer.fromJson(value) : null; + // } + // return true; + ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(itemSerializer), + 'fillFromJson' + ), + [], + [ + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('obj'), + fieldName + ), + ts.factory.createIdentifier('value') + ] + ) + ), + assignField( + type.isNullable + ? ts.factory.createConditionalExpression( + ts.factory.createIdentifier('value'), + ts.factory.createToken(ts.SyntaxKind.QuestionToken), + ts.factory.createCallExpression( + // TypeName.fromJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ + ts.factory.createIdentifier('value') + ] + ), + ts.factory.createToken(ts.SyntaxKind.ColonToken), + ts.factory.createNull() + ) + : ts.factory.createCallExpression( + // TypeName.fromJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ + ts.factory.createIdentifier('value') + ] + ) + ) + ), + ts.factory.createReturnStatement(ts.factory.createTrue()) + ]), + ts.factory.createBlock([ + // for(const candidate of ["", "core"]) { + // if(candidate.indexOf(property) === 0) { + // if(!this.field) { this.field = new FieldType(); } + // if(this.field.setProperty(property.substring(candidate.length), value)) return true; + // } + // } + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('$c')], ts.NodeFlags.Const), + jsonNameArray, + ts.factory.createIfStatement( + ts.factory.createBinaryExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('property'), 'indexOf'), + [], + [ts.factory.createIdentifier('$c')] + ), + ts.SyntaxKind.EqualsEqualsEqualsToken, + ts.factory.createNumericLiteral('0') + ), + ts.factory.createBlock([ + ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) + ), + ts.factory.createBlock([ + assignField(ts.factory.createNewExpression(ts.factory.createIdentifier(type.type!.symbol!.name), [], [])) + ]) + ), + ts.factory.createIfStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(itemSerializer), + 'setProperty' + ), + [], + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('property'), + 'substring' + ), + [], + [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$c'), 'length')] + ), + ts.factory.createIdentifier('value') + ] + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement(ts.factory.createTrue()) + ]) + ) + ]) + ) + ) + ]) + ) + ); + } + + if (caseStatements.length > 0) { + for (let i = 0; i < caseValues.length; i++) { + cases.push( + ts.factory.createCaseClause( + ts.factory.createStringLiteral(caseValues[i]), + // last case gets the statements, others are fall through + i < caseValues.length - 1 ? [] : caseStatements + ) + ); + } + } + } + + const switchExpr = ts.factory.createSwitchStatement(ts.factory.createIdentifier('property'), ts.factory.createCaseBlock(cases)); + statements.unshift(switchExpr); + statements.push(ts.factory.createReturnStatement(ts.factory.createFalse())); + + return ts.factory.createBlock(addNewLines(statements)); +} + +function createSetPropertyMethod( + program: ts.Program, + input: ts.ClassDeclaration, + propertiesToSerialize: JsonProperty[], + importer: (name: string, module: string) => void +) { + return ts.factory.createMethodDeclaration( + undefined, + [ + ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), + ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) + ], + undefined, + 'setProperty', + undefined, + undefined, + [ + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'obj', + undefined, + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ) + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'property', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword) + ), + ts.factory.createParameterDeclaration( + undefined, + undefined, + undefined, + 'value', + undefined, + ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ) + ], + ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), + generateSetPropertyBody(program, propertiesToSerialize, importer) + ) +} + +export default createEmitter('json', (program, input) => { + console.log(`Writing Serializer for ${input.name!.text}`); + const sourceFileName = path.relative( + path.join(path.resolve(program.getCompilerOptions().baseUrl!)), + path.resolve(input.getSourceFile().fileName) + ); + + let propertiesToSerialize: JsonProperty[] = []; + input.members.forEach(member => { + if (ts.isPropertyDeclaration(member)) { + const propertyDeclaration = member as ts.PropertyDeclaration; + if (!propertyDeclaration.modifiers!.find(m => + m.kind === ts.SyntaxKind.StaticKeyword || + m.kind === ts.SyntaxKind.PrivateKeyword || + m.kind === ts.SyntaxKind.ReadonlyKeyword)) { + const jsonNames = [(member.name as ts.Identifier).text]; + + if (ts.getJSDocTags(member).find(t => t.tagName.text === 'json_on_parent')) { + jsonNames.push(''); + } + + if (!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_ignore')) { + propertiesToSerialize.push({ + property: propertyDeclaration, + jsonNames: jsonNames + }); + } + } + } + }); + + const statements: ts.Statement[] = []; + + const importedNames = new Set(); + function importer(name: string, module: string) { + if (importedNames.has(name)) { + return; + } + importedNames.add(name); + statements.push(ts.factory.createImportDeclaration( + undefined, + undefined, + ts.factory.createImportClause( + false, + undefined, + ts.factory.createNamedImports([ts.factory.createImportSpecifier( + undefined, + ts.factory.createIdentifier(name) + )]) + ), + ts.factory.createStringLiteral(module) + )) + } + + statements.push(ts.factory.createClassDeclaration( + [], + [ + ts.factory.createModifier(ts.SyntaxKind.ExportKeyword), + ], + input.name!.text + 'Serializer', + undefined, + undefined, + [ + createFromJsonMethod(input), + createFillFromJsonMethod(input), + createToJsonMethod(input), + createFillToJsonMethod(program, input, propertiesToSerialize, importer), + createSetPropertyMethod(program, input, propertiesToSerialize, importer) + ] + )); + + const sourceFile = ts.factory.createSourceFile([ + ts.factory.createImportDeclaration( + undefined, + undefined, + ts.factory.createImportClause(false, + undefined, + ts.factory.createNamedImports([ts.factory.createImportSpecifier( + undefined, + ts.factory.createIdentifier(input.name!.text) + )]) + ), + ts.factory.createStringLiteral(toImportPath(sourceFileName)) + ), + ...statements + ], ts.factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None); + + return sourceFile; +}); \ No newline at end of file diff --git a/src/Settings.ts b/src/Settings.ts index 3ea1c169d..41480db3b 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -3,49 +3,19 @@ import { DisplaySettings } from '@src/DisplaySettings'; import { ImporterSettings } from '@src/ImporterSettings'; import { FingeringMode, NotationMode, NotationSettings, NotationElement } from '@src/NotationSettings'; import { PlayerSettings } from '@src/PlayerSettings'; +import { SettingsSerializer } from './generated/SettingsSerializer'; /** * This public class contains instance specific settings for alphaTab * @json */ export class Settings { - /** - * @target web - */ - public static fromJson(json: any): Settings { - // dynamically implemented via AST transformer - return new Settings(); - } - - /** - * @target web - */ - public fillFromJson(json: any): void { - // dynamically implemented via AST transformer - } - - /** - * @target web - */ - public static toJson(settings: Settings): unknown { - // dynamically implemented via AST transformer - return null; - } - - /** - * @target web - */ - public setProperty(property: string, value: any): boolean { - // dynamically implemented via AST transformer - return false; - } - /** * @target web */ public fillFromDataAttributes(dataAttributes: Map): void { dataAttributes.forEach((v, k) => { - this.setProperty(k.toLowerCase(), v); + SettingsSerializer.setProperty(this, k.toLowerCase(), v); }); } diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts new file mode 100644 index 000000000..9a621873a --- /dev/null +++ b/src/generated/CoreSettingsSerializer.ts @@ -0,0 +1,81 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { CoreSettings } from "@src/CoreSettings"; +import { LogLevel } from "@src/LogLevel"; +export class CoreSettingsSerializer { + public static fromJson(json: any): CoreSettings { + const obj = new CoreSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: CoreSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: CoreSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: CoreSettings, json: any): void { + json.scriptFile = obj.scriptFile; + json.fontDirectory = obj.fontDirectory; + json.file = obj.file; + json.tex = obj.tex; + json.tracks = obj.tracks; + json.visibilityCheckInterval = obj.visibilityCheckInterval; + json.enableLazyLoading = obj.enableLazyLoading; + json.engine = obj.engine; + json.logLevel = obj.logLevel; + json.useWorkers = obj.useWorkers; + json.includeNoteBounds = obj.includeNoteBounds; + } + public static setProperty(obj: CoreSettings, property: string, value: any): boolean { + switch (property) { + case "scriptfile": + obj.scriptFile = value; + return true; + case "fontdirectory": + obj.fontDirectory = value; + return true; + case "file": + obj.file = value; + return true; + case "tex": + obj.tex = value; + return true; + case "tracks": + obj.tracks = value; + return true; + case "visibilitycheckinterval": + obj.visibilityCheckInterval = value; + return true; + case "enablelazyloading": + obj.enableLazyLoading = value; + return true; + case "engine": + obj.engine = value; + return true; + case "loglevel": + obj.logLevel = isNaN(parseInt(value)) ? LogLevel[Object.keys(LogLevel).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof LogLevel] : parseInt(value); + return true; + case "useworkers": + obj.useWorkers = value; + return true; + case "includenotebounds": + obj.includeNoteBounds = value; + return true; + } + return false; + } +} + diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts new file mode 100644 index 000000000..7181dd918 --- /dev/null +++ b/src/generated/DisplaySettingsSerializer.ts @@ -0,0 +1,100 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { DisplaySettings } from "@src/DisplaySettings"; +import { RenderingResourcesSerializer } from "@src/generated/RenderingResourcesSerializer"; +import { LayoutMode } from "@src/DisplaySettings"; +import { StaveProfile } from "@src/DisplaySettings"; +import { RenderingResources } from "@src/RenderingResources"; +export class DisplaySettingsSerializer { + public static fromJson(json: any): DisplaySettings { + const obj = new DisplaySettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: DisplaySettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: DisplaySettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: DisplaySettings, json: any): void { + json.scale = obj.scale; + json.stretchForce = obj.stretchForce; + json.layoutMode = obj.layoutMode; + json.staveProfile = obj.staveProfile; + json.barsPerRow = obj.barsPerRow; + json.startBar = obj.startBar; + json.barCount = obj.barCount; + json.barCountPerPartial = obj.barCountPerPartial; + if (json.resources) { + RenderingResourcesSerializer.fillToJson(obj.resources, json.resources); + } + else { + json.resources = (RenderingResourcesSerializer.toJson(obj.resources)!); + } + json.padding = obj.padding ? obj.padding.slice() : null; + } + public static setProperty(obj: DisplaySettings, property: string, value: any): boolean { + switch (property) { + case "scale": + obj.scale = value; + return true; + case "stretchforce": + obj.stretchForce = value; + return true; + case "layoutmode": + obj.layoutMode = isNaN(parseInt(value)) ? LayoutMode[Object.keys(LayoutMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof LayoutMode] : parseInt(value); + return true; + case "staveprofile": + obj.staveProfile = isNaN(parseInt(value)) ? StaveProfile[Object.keys(StaveProfile).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof StaveProfile] : parseInt(value); + return true; + case "barsperrow": + obj.barsPerRow = value; + return true; + case "startbar": + obj.startBar = value; + return true; + case "barcount": + obj.barCount = value; + return true; + case "barcountperpartial": + obj.barCountPerPartial = value; + return true; + case "padding": + obj.padding = value ? value.slice() : null; + return true; + } + if (["resources"].indexOf(property) >= 0) { + if (obj.resources) + RenderingResourcesSerializer.fillFromJson(obj.resources, value); + else + obj.resources = RenderingResourcesSerializer.fromJson(value); + return true; + } + else { + for (const $c of ["resources"]) + if (property.indexOf($c) === 0) { + if (!obj.resources) { + obj.resources = new RenderingResources(); + } + if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring($c.length), value)) { + return true; + } + } + } + return false; + } +} + diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts new file mode 100644 index 000000000..5ca67b845 --- /dev/null +++ b/src/generated/ImporterSettingsSerializer.ts @@ -0,0 +1,44 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { ImporterSettings } from "@src/ImporterSettings"; +export class ImporterSettingsSerializer { + public static fromJson(json: any): ImporterSettings { + const obj = new ImporterSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: ImporterSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: ImporterSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: ImporterSettings, json: any): void { + json.encoding = obj.encoding; + json.mergePartGroupsInMusicXml = obj.mergePartGroupsInMusicXml; + } + public static setProperty(obj: ImporterSettings, property: string, value: any): boolean { + switch (property) { + case "encoding": + obj.encoding = value; + return true; + case "mergepartgroupsinmusicxml": + obj.mergePartGroupsInMusicXml = value; + return true; + } + return false; + } +} + diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts new file mode 100644 index 000000000..bd5ea3a4b --- /dev/null +++ b/src/generated/NotationSettingsSerializer.ts @@ -0,0 +1,88 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { NotationSettings } from "@src/NotationSettings"; +import { NotationMode } from "@src/NotationSettings"; +import { FingeringMode } from "@src/NotationSettings"; +import { NotationElement } from "@src/NotationSettings"; +import { TabRhythmMode } from "@src/NotationSettings"; +export class NotationSettingsSerializer { + public static fromJson(json: any): NotationSettings { + const obj = new NotationSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: NotationSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: NotationSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: NotationSettings, json: any): void { + json.notationMode = obj.notationMode; + json.fingeringMode = obj.fingeringMode; + json.elements = ({} as any); + obj.elements.forEach(($mv, $mk) => { (json.elements as any)[$mk] = $mv; }); + json.rhythmMode = obj.rhythmMode; + json.rhythmHeight = obj.rhythmHeight; + json.transpositionPitches = obj.transpositionPitches.slice(); + json.displayTranspositionPitches = obj.displayTranspositionPitches.slice(); + json.smallGraceTabNotes = obj.smallGraceTabNotes; + json.extendBendArrowsOnTiedNotes = obj.extendBendArrowsOnTiedNotes; + json.extendLineEffectsToBeatEnd = obj.extendLineEffectsToBeatEnd; + json.slurHeight = obj.slurHeight; + } + public static setProperty(obj: NotationSettings, property: string, value: any): boolean { + switch (property) { + case "notationmode": + obj.notationMode = isNaN(parseInt(value)) ? NotationMode[Object.keys(NotationMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof NotationMode] : parseInt(value); + return true; + case "fingeringmode": + obj.fingeringMode = isNaN(parseInt(value)) ? FingeringMode[Object.keys(FingeringMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof FingeringMode] : parseInt(value); + return true; + case "elements": + obj.elements = new Map(); + for (let $mk in value) + if (value.hasOwnProperty($mk)) + obj.elements.set(isNaN(parseInt($mk)) ? NotationElement[Object.keys(NotationElement).find($k => $k.toLowerCase() === $mk.toLowerCase()) as keyof typeof NotationElement] : parseInt($mk), value[$mk]); + return true; + case "rhythmmode": + obj.rhythmMode = isNaN(parseInt(value)) ? TabRhythmMode[Object.keys(TabRhythmMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TabRhythmMode] : parseInt(value); + return true; + case "rhythmheight": + obj.rhythmHeight = value; + return true; + case "transpositionpitches": + obj.transpositionPitches = value.slice(); + return true; + case "displaytranspositionpitches": + obj.displayTranspositionPitches = value.slice(); + return true; + case "smallgracetabnotes": + obj.smallGraceTabNotes = value; + return true; + case "extendbendarrowsontiednotes": + obj.extendBendArrowsOnTiedNotes = value; + return true; + case "extendlineeffectstobeatend": + obj.extendLineEffectsToBeatEnd = value; + return true; + case "slurheight": + obj.slurHeight = value; + return true; + } + return false; + } +} + diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts new file mode 100644 index 000000000..09344ca80 --- /dev/null +++ b/src/generated/PlayerSettingsSerializer.ts @@ -0,0 +1,85 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { PlayerSettings } from "@src/PlayerSettings"; +import { ScrollMode } from "@src/PlayerSettings"; +export class PlayerSettingsSerializer { + public static fromJson(json: any): PlayerSettings { + const obj = new PlayerSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: PlayerSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: PlayerSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: PlayerSettings, json: any): void { + json.soundFont = obj.soundFont; + json.scrollElement = obj.scrollElement; + json.enablePlayer = obj.enablePlayer; + json.enableCursor = obj.enableCursor; + json.enableUserInteraction = obj.enableUserInteraction; + json.scrollOffsetX = obj.scrollOffsetX; + json.scrollOffsetY = obj.scrollOffsetY; + json.scrollMode = obj.scrollMode; + json.scrollSpeed = obj.scrollSpeed; + json.songBookBendDuration = obj.songBookBendDuration; + json.songBookDipDuration = obj.songBookDipDuration; + json.playTripletFeel = obj.playTripletFeel; + } + public static setProperty(obj: PlayerSettings, property: string, value: any): boolean { + switch (property) { + case "soundfont": + obj.soundFont = value; + return true; + case "scrollelement": + obj.scrollElement = value; + return true; + case "enableplayer": + obj.enablePlayer = value; + return true; + case "enablecursor": + obj.enableCursor = value; + return true; + case "enableuserinteraction": + obj.enableUserInteraction = value; + return true; + case "scrolloffsetx": + obj.scrollOffsetX = value; + return true; + case "scrolloffsety": + obj.scrollOffsetY = value; + return true; + case "scrollmode": + obj.scrollMode = isNaN(parseInt(value)) ? ScrollMode[Object.keys(ScrollMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof ScrollMode] : parseInt(value); + return true; + case "scrollspeed": + obj.scrollSpeed = value; + return true; + case "songbookbendduration": + obj.songBookBendDuration = value; + return true; + case "songbookdipduration": + obj.songBookDipDuration = value; + return true; + case "playtripletfeel": + obj.playTripletFeel = value; + return true; + } + return false; + } +} + diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts new file mode 100644 index 000000000..7b158fb30 --- /dev/null +++ b/src/generated/RenderingResourcesSerializer.ts @@ -0,0 +1,106 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { RenderingResources } from "@src/RenderingResources"; +import { Font } from "@src/model/Font"; +import { Color } from "@src/model/Color"; +export class RenderingResourcesSerializer { + public static fromJson(json: any): RenderingResources { + const obj = new RenderingResources(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: RenderingResources, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: RenderingResources | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: RenderingResources, json: any): void { + json.copyrightFont = (Font.toJson(obj.copyrightFont)!); + json.titleFont = (Font.toJson(obj.titleFont)!); + json.subTitleFont = (Font.toJson(obj.subTitleFont)!); + json.wordsFont = (Font.toJson(obj.wordsFont)!); + json.effectFont = (Font.toJson(obj.effectFont)!); + json.fretboardNumberFont = (Font.toJson(obj.fretboardNumberFont)!); + json.tablatureFont = (Font.toJson(obj.tablatureFont)!); + json.graceFont = (Font.toJson(obj.graceFont)!); + json.staffLineColor = (Color.toJson(obj.staffLineColor)!); + json.barSeparatorColor = (Color.toJson(obj.barSeparatorColor)!); + json.barNumberFont = (Font.toJson(obj.barNumberFont)!); + json.barNumberColor = (Color.toJson(obj.barNumberColor)!); + json.fingeringFont = (Font.toJson(obj.fingeringFont)!); + json.markerFont = (Font.toJson(obj.markerFont)!); + json.mainGlyphColor = (Color.toJson(obj.mainGlyphColor)!); + json.secondaryGlyphColor = (Color.toJson(obj.secondaryGlyphColor)!); + json.scoreInfoColor = (Color.toJson(obj.scoreInfoColor)!); + } + public static setProperty(obj: RenderingResources, property: string, value: any): boolean { + switch (property) { + case "copyrightfont": + obj.copyrightFont = (Font.fromJson(value)!); + return true; + case "titlefont": + obj.titleFont = (Font.fromJson(value)!); + return true; + case "subtitlefont": + obj.subTitleFont = (Font.fromJson(value)!); + return true; + case "wordsfont": + obj.wordsFont = (Font.fromJson(value)!); + return true; + case "effectfont": + obj.effectFont = (Font.fromJson(value)!); + return true; + case "fretboardnumberfont": + obj.fretboardNumberFont = (Font.fromJson(value)!); + return true; + case "tablaturefont": + obj.tablatureFont = (Font.fromJson(value)!); + return true; + case "gracefont": + obj.graceFont = (Font.fromJson(value)!); + return true; + case "stafflinecolor": + obj.staffLineColor = (Color.fromJson(value)!); + return true; + case "barseparatorcolor": + obj.barSeparatorColor = (Color.fromJson(value)!); + return true; + case "barnumberfont": + obj.barNumberFont = (Font.fromJson(value)!); + return true; + case "barnumbercolor": + obj.barNumberColor = (Color.fromJson(value)!); + return true; + case "fingeringfont": + obj.fingeringFont = (Font.fromJson(value)!); + return true; + case "markerfont": + obj.markerFont = (Font.fromJson(value)!); + return true; + case "mainglyphcolor": + obj.mainGlyphColor = (Color.fromJson(value)!); + return true; + case "secondaryglyphcolor": + obj.secondaryGlyphColor = (Color.fromJson(value)!); + return true; + case "scoreinfocolor": + obj.scoreInfoColor = (Color.fromJson(value)!); + return true; + } + return false; + } +} + diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts new file mode 100644 index 000000000..2a821759a --- /dev/null +++ b/src/generated/SettingsSerializer.ts @@ -0,0 +1,35 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Settings } from "@src/Settings"; +export class SettingsSerializer { + public static fromJson(json: any): Settings { + const obj = new Settings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Settings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Settings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Settings, json: any): void { } + public static setProperty(obj: Settings, property: string, value: any): boolean { + switch (property) { + } + return false; + } +} + diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts new file mode 100644 index 000000000..9286d5796 --- /dev/null +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -0,0 +1,48 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { SlidePlaybackSettings } from "@src/PlayerSettings"; +export class SlidePlaybackSettingsSerializer { + public static fromJson(json: any): SlidePlaybackSettings { + const obj = new SlidePlaybackSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: SlidePlaybackSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: SlidePlaybackSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: SlidePlaybackSettings, json: any): void { + json.simpleSlidePitchOffset = obj.simpleSlidePitchOffset; + json.simpleSlideDurationRatio = obj.simpleSlideDurationRatio; + json.shiftSlideDurationRatio = obj.shiftSlideDurationRatio; + } + public static setProperty(obj: SlidePlaybackSettings, property: string, value: any): boolean { + switch (property) { + case "simpleslidepitchoffset": + obj.simpleSlidePitchOffset = value; + return true; + case "simpleslidedurationratio": + obj.simpleSlideDurationRatio = value; + return true; + case "shiftslidedurationratio": + obj.shiftSlideDurationRatio = value; + return true; + } + return false; + } +} + diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts new file mode 100644 index 000000000..877bad139 --- /dev/null +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -0,0 +1,68 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { VibratoPlaybackSettings } from "@src/PlayerSettings"; +export class VibratoPlaybackSettingsSerializer { + public static fromJson(json: any): VibratoPlaybackSettings { + const obj = new VibratoPlaybackSettings(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: VibratoPlaybackSettings, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: VibratoPlaybackSettings | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: VibratoPlaybackSettings, json: any): void { + json.noteWideLength = obj.noteWideLength; + json.noteWideAmplitude = obj.noteWideAmplitude; + json.noteSlightLength = obj.noteSlightLength; + json.noteSlightAmplitude = obj.noteSlightAmplitude; + json.beatWideLength = obj.beatWideLength; + json.beatWideAmplitude = obj.beatWideAmplitude; + json.beatSlightLength = obj.beatSlightLength; + json.beatSlightAmplitude = obj.beatSlightAmplitude; + } + public static setProperty(obj: VibratoPlaybackSettings, property: string, value: any): boolean { + switch (property) { + case "notewidelength": + obj.noteWideLength = value; + return true; + case "notewideamplitude": + obj.noteWideAmplitude = value; + return true; + case "noteslightlength": + obj.noteSlightLength = value; + return true; + case "noteslightamplitude": + obj.noteSlightAmplitude = value; + return true; + case "beatwidelength": + obj.beatWideLength = value; + return true; + case "beatwideamplitude": + obj.beatWideAmplitude = value; + return true; + case "beatslightlength": + obj.beatSlightLength = value; + return true; + case "beatslightamplitude": + obj.beatSlightAmplitude = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/AutomationCloner.ts b/src/generated/model/AutomationCloner.ts new file mode 100644 index 000000000..fc0e50ff6 --- /dev/null +++ b/src/generated/model/AutomationCloner.ts @@ -0,0 +1,18 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Automation } from "@src/model/Automation"; +export class AutomationCloner { + public static clone(original: Automation): Automation { + const clone = new Automation(); + clone.isLinear = original.isLinear; + clone.type = original.type; + clone.value = original.value; + clone.ratioPosition = original.ratioPosition; + clone.text = original.text; + return clone; + } +} + diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts new file mode 100644 index 000000000..0a0cc2357 --- /dev/null +++ b/src/generated/model/AutomationSerializer.ts @@ -0,0 +1,57 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Automation } from "@src/model/Automation"; +import { AutomationType } from "@src/model/Automation"; +export class AutomationSerializer { + public static fromJson(json: any): Automation { + const obj = new Automation(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Automation, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Automation | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Automation, json: any): void { + json.isLinear = obj.isLinear; + json.type = obj.type; + json.value = obj.value; + json.ratioPosition = obj.ratioPosition; + json.text = obj.text; + } + public static setProperty(obj: Automation, property: string, value: any): boolean { + switch (property) { + case "islinear": + obj.isLinear = value; + return true; + case "type": + obj.type = isNaN(parseInt(value)) ? AutomationType[Object.keys(AutomationType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof AutomationType] : parseInt(value); + return true; + case "value": + obj.value = value; + return true; + case "ratioposition": + obj.ratioPosition = value; + return true; + case "text": + obj.text = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts new file mode 100644 index 000000000..05164fcbd --- /dev/null +++ b/src/generated/model/BarSerializer.ts @@ -0,0 +1,66 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Bar } from "@src/model/Bar"; +import { VoiceSerializer } from "@src/generated/model/VoiceSerializer"; +import { Clef } from "@src/model/Clef"; +import { Ottavia } from "@src/model/Ottavia"; +import { SimileMark } from "@src/model/SimileMark"; +export class BarSerializer { + public static fromJson(json: any): Bar { + const obj = new Bar(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Bar, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Bar | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Bar, json: any): void { + json.id = obj.id; + json.index = obj.index; + json.clef = obj.clef; + json.clefOttava = obj.clefOttava; + json.voices = obj.voices.map($li => VoiceSerializer.toJson($li)); + json.simileMark = obj.simileMark; + } + public static setProperty(obj: Bar, property: string, value: any): boolean { + switch (property) { + case "id": + obj.id = value; + return true; + case "index": + obj.index = value; + return true; + case "clef": + obj.clef = isNaN(parseInt(value)) ? Clef[Object.keys(Clef).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Clef] : parseInt(value); + return true; + case "clefottava": + obj.clefOttava = isNaN(parseInt(value)) ? Ottavia[Object.keys(Ottavia).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Ottavia] : parseInt(value); + return true; + case "voices": + obj.voices = []; + for (const $li of value) + obj.addVoice(VoiceSerializer.fromJson($li)); + return true; + case "similemark": + obj.simileMark = isNaN(parseInt(value)) ? SimileMark[Object.keys(SimileMark).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SimileMark] : parseInt(value); + return true; + } + return false; + } +} + diff --git a/src/generated/model/BeatCloner.ts b/src/generated/model/BeatCloner.ts new file mode 100644 index 000000000..f9396dbb8 --- /dev/null +++ b/src/generated/model/BeatCloner.ts @@ -0,0 +1,65 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Beat } from "@src/model/Beat"; +import { NoteCloner } from "./NoteCloner"; +import { AutomationCloner } from "./AutomationCloner"; +import { BendPointCloner } from "./BendPointCloner"; +export class BeatCloner { + public static clone(original: Beat): Beat { + const clone = new Beat(); + clone.index = original.index; + clone.notes = []; + for (const i of original.notes) { + clone.addNote(NoteCloner.clone(i)); + } + clone.isEmpty = original.isEmpty; + clone.whammyStyle = original.whammyStyle; + clone.ottava = original.ottava; + clone.isLegatoOrigin = original.isLegatoOrigin; + clone.duration = original.duration; + clone.isLetRing = original.isLetRing; + clone.isPalmMute = original.isPalmMute; + clone.automations = []; + for (const i of original.automations) { + clone.automations.push(AutomationCloner.clone(i)); + } + clone.dots = original.dots; + clone.fadeIn = original.fadeIn; + clone.lyrics = original.lyrics ? original.lyrics.slice() : null; + clone.hasRasgueado = original.hasRasgueado; + clone.pop = original.pop; + clone.slap = original.slap; + clone.tap = original.tap; + clone.text = original.text; + clone.brushType = original.brushType; + clone.brushDuration = original.brushDuration; + clone.tupletDenominator = original.tupletDenominator; + clone.tupletNumerator = original.tupletNumerator; + clone.isContinuedWhammy = original.isContinuedWhammy; + clone.whammyBarType = original.whammyBarType; + clone.whammyBarPoints = []; + for (const i of original.whammyBarPoints) { + clone.addWhammyBarPoint(BendPointCloner.clone(i)); + } + clone.vibrato = original.vibrato; + clone.chordId = original.chordId; + clone.graceType = original.graceType; + clone.pickStroke = original.pickStroke; + clone.tremoloSpeed = original.tremoloSpeed; + clone.crescendo = original.crescendo; + clone.displayStart = original.displayStart; + clone.playbackStart = original.playbackStart; + clone.displayDuration = original.displayDuration; + clone.playbackDuration = original.playbackDuration; + clone.dynamics = original.dynamics; + clone.invertBeamDirection = original.invertBeamDirection; + clone.preferredBeamDirection = original.preferredBeamDirection; + clone.isEffectSlurOrigin = original.isEffectSlurOrigin; + clone.beamingMode = original.beamingMode; + return clone; + } +} + diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts new file mode 100644 index 000000000..0b0bedcfa --- /dev/null +++ b/src/generated/model/BeatSerializer.ts @@ -0,0 +1,221 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Beat } from "@src/model/Beat"; +import { NoteSerializer } from "@src/generated/model/NoteSerializer"; +import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; +import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; +import { BendStyle } from "@src/model/BendStyle"; +import { Ottavia } from "@src/model/Ottavia"; +import { Duration } from "@src/model/Duration"; +import { BrushType } from "@src/model/BrushType"; +import { WhammyType } from "@src/model/WhammyType"; +import { VibratoType } from "@src/model/VibratoType"; +import { GraceType } from "@src/model/GraceType"; +import { PickStroke } from "@src/model/PickStroke"; +import { CrescendoType } from "@src/model/CrescendoType"; +import { DynamicValue } from "@src/model/DynamicValue"; +import { BeamDirection } from "@src/rendering/utils/BeamDirection"; +import { BeatBeamingMode } from "@src/model/Beat"; +export class BeatSerializer { + public static fromJson(json: any): Beat { + const obj = new Beat(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Beat, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Beat | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Beat, json: any): void { + json.id = obj.id; + json.index = obj.index; + json.notes = obj.notes.map($li => NoteSerializer.toJson($li)); + json.isEmpty = obj.isEmpty; + json.whammyStyle = obj.whammyStyle; + json.ottava = obj.ottava; + json.isLegatoOrigin = obj.isLegatoOrigin; + json.duration = obj.duration; + json.isLetRing = obj.isLetRing; + json.isPalmMute = obj.isPalmMute; + json.automations = obj.automations.map($li => AutomationSerializer.toJson($li)); + json.dots = obj.dots; + json.fadeIn = obj.fadeIn; + json.lyrics = obj.lyrics ? obj.lyrics.slice() : null; + json.hasRasgueado = obj.hasRasgueado; + json.pop = obj.pop; + json.slap = obj.slap; + json.tap = obj.tap; + json.text = obj.text; + json.brushType = obj.brushType; + json.brushDuration = obj.brushDuration; + json.tupletDenominator = obj.tupletDenominator; + json.tupletNumerator = obj.tupletNumerator; + json.isContinuedWhammy = obj.isContinuedWhammy; + json.whammyBarType = obj.whammyBarType; + json.whammyBarPoints = obj.whammyBarPoints.map($li => BendPointSerializer.toJson($li)); + json.vibrato = obj.vibrato; + json.chordId = obj.chordId; + json.graceType = obj.graceType; + json.pickStroke = obj.pickStroke; + json.tremoloSpeed = obj.tremoloSpeed; + json.crescendo = obj.crescendo; + json.displayStart = obj.displayStart; + json.playbackStart = obj.playbackStart; + json.displayDuration = obj.displayDuration; + json.playbackDuration = obj.playbackDuration; + json.dynamics = obj.dynamics; + json.invertBeamDirection = obj.invertBeamDirection; + json.preferredBeamDirection = obj.preferredBeamDirection; + json.isEffectSlurOrigin = obj.isEffectSlurOrigin; + json.beamingMode = obj.beamingMode; + } + public static setProperty(obj: Beat, property: string, value: any): boolean { + switch (property) { + case "id": + obj.id = value; + return true; + case "index": + obj.index = value; + return true; + case "notes": + obj.notes = []; + for (const $li of value) + obj.addNote(NoteSerializer.fromJson($li)); + return true; + case "isempty": + obj.isEmpty = value; + return true; + case "whammystyle": + obj.whammyStyle = isNaN(parseInt(value)) ? BendStyle[Object.keys(BendStyle).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendStyle] : parseInt(value); + return true; + case "ottava": + obj.ottava = isNaN(parseInt(value)) ? Ottavia[Object.keys(Ottavia).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Ottavia] : parseInt(value); + return true; + case "islegatoorigin": + obj.isLegatoOrigin = value; + return true; + case "duration": + obj.duration = isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + return true; + case "isletring": + obj.isLetRing = value; + return true; + case "ispalmmute": + obj.isPalmMute = value; + return true; + case "automations": + obj.automations = []; + for (const $li of value) + obj.automations.push(AutomationSerializer.fromJson($li)); + return true; + case "dots": + obj.dots = value; + return true; + case "fadein": + obj.fadeIn = value; + return true; + case "lyrics": + obj.lyrics = value ? value.slice() : null; + return true; + case "hasrasgueado": + obj.hasRasgueado = value; + return true; + case "pop": + obj.pop = value; + return true; + case "slap": + obj.slap = value; + return true; + case "tap": + obj.tap = value; + return true; + case "text": + obj.text = value; + return true; + case "brushtype": + obj.brushType = isNaN(parseInt(value)) ? BrushType[Object.keys(BrushType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BrushType] : parseInt(value); + return true; + case "brushduration": + obj.brushDuration = value; + return true; + case "tupletdenominator": + obj.tupletDenominator = value; + return true; + case "tupletnumerator": + obj.tupletNumerator = value; + return true; + case "iscontinuedwhammy": + obj.isContinuedWhammy = value; + return true; + case "whammybartype": + obj.whammyBarType = isNaN(parseInt(value)) ? WhammyType[Object.keys(WhammyType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof WhammyType] : parseInt(value); + return true; + case "whammybarpoints": + obj.whammyBarPoints = []; + for (const $li of value) + obj.addWhammyBarPoint(BendPointSerializer.fromJson($li)); + return true; + case "vibrato": + obj.vibrato = isNaN(parseInt(value)) ? VibratoType[Object.keys(VibratoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof VibratoType] : parseInt(value); + return true; + case "chordid": + obj.chordId = value; + return true; + case "gracetype": + obj.graceType = isNaN(parseInt(value)) ? GraceType[Object.keys(GraceType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof GraceType] : parseInt(value); + return true; + case "pickstroke": + obj.pickStroke = isNaN(parseInt(value)) ? PickStroke[Object.keys(PickStroke).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof PickStroke] : parseInt(value); + return true; + case "tremolospeed": + obj.tremoloSpeed = value === null ? null : isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + return true; + case "crescendo": + obj.crescendo = isNaN(parseInt(value)) ? CrescendoType[Object.keys(CrescendoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof CrescendoType] : parseInt(value); + return true; + case "displaystart": + obj.displayStart = value; + return true; + case "playbackstart": + obj.playbackStart = value; + return true; + case "displayduration": + obj.displayDuration = value; + return true; + case "playbackduration": + obj.playbackDuration = value; + return true; + case "dynamics": + obj.dynamics = isNaN(parseInt(value)) ? DynamicValue[Object.keys(DynamicValue).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof DynamicValue] : parseInt(value); + return true; + case "invertbeamdirection": + obj.invertBeamDirection = value; + return true; + case "preferredbeamdirection": + obj.preferredBeamDirection = value === null ? null : isNaN(parseInt(value)) ? BeamDirection[Object.keys(BeamDirection).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BeamDirection] : parseInt(value); + return true; + case "iseffectslurorigin": + obj.isEffectSlurOrigin = value; + return true; + case "beamingmode": + obj.beamingMode = isNaN(parseInt(value)) ? BeatBeamingMode[Object.keys(BeatBeamingMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BeatBeamingMode] : parseInt(value); + return true; + } + return false; + } +} + diff --git a/src/generated/model/BendPointCloner.ts b/src/generated/model/BendPointCloner.ts new file mode 100644 index 000000000..41a8dea7f --- /dev/null +++ b/src/generated/model/BendPointCloner.ts @@ -0,0 +1,15 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { BendPoint } from "@src/model/BendPoint"; +export class BendPointCloner { + public static clone(original: BendPoint): BendPoint { + const clone = new BendPoint(); + clone.offset = original.offset; + clone.value = original.value; + return clone; + } +} + diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts new file mode 100644 index 000000000..da5821063 --- /dev/null +++ b/src/generated/model/BendPointSerializer.ts @@ -0,0 +1,44 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { BendPoint } from "@src/model/BendPoint"; +export class BendPointSerializer { + public static fromJson(json: any): BendPoint { + const obj = new BendPoint(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: BendPoint, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: BendPoint | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: BendPoint, json: any): void { + json.offset = obj.offset; + json.value = obj.value; + } + public static setProperty(obj: BendPoint, property: string, value: any): boolean { + switch (property) { + case "offset": + obj.offset = value; + return true; + case "value": + obj.value = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts new file mode 100644 index 000000000..043d441aa --- /dev/null +++ b/src/generated/model/ChordSerializer.ts @@ -0,0 +1,64 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Chord } from "@src/model/Chord"; +export class ChordSerializer { + public static fromJson(json: any): Chord { + const obj = new Chord(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Chord, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Chord | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Chord, json: any): void { + json.name = obj.name; + json.firstFret = obj.firstFret; + json.strings = obj.strings.slice(); + json.barreFrets = obj.barreFrets.slice(); + json.showName = obj.showName; + json.showDiagram = obj.showDiagram; + json.showFingering = obj.showFingering; + } + public static setProperty(obj: Chord, property: string, value: any): boolean { + switch (property) { + case "name": + obj.name = value; + return true; + case "firstfret": + obj.firstFret = value; + return true; + case "strings": + obj.strings = value.slice(); + return true; + case "barrefrets": + obj.barreFrets = value.slice(); + return true; + case "showname": + obj.showName = value; + return true; + case "showdiagram": + obj.showDiagram = value; + return true; + case "showfingering": + obj.showFingering = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts new file mode 100644 index 000000000..6ba1d326e --- /dev/null +++ b/src/generated/model/FermataSerializer.ts @@ -0,0 +1,45 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Fermata } from "@src/model/Fermata"; +import { FermataType } from "@src/model/Fermata"; +export class FermataSerializer { + public static fromJson(json: any): Fermata { + const obj = new Fermata(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Fermata, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Fermata | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Fermata, json: any): void { + json.type = obj.type; + json.length = obj.length; + } + public static setProperty(obj: Fermata, property: string, value: any): boolean { + switch (property) { + case "type": + obj.type = isNaN(parseInt(value)) ? FermataType[Object.keys(FermataType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof FermataType] : parseInt(value); + return true; + case "length": + obj.length = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts new file mode 100644 index 000000000..03a6274c6 --- /dev/null +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -0,0 +1,66 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; +import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; +import { TextBaseline } from "@src/platform/ICanvas"; +export class InstrumentArticulationSerializer { + public static fromJson(json: any): InstrumentArticulation { + const obj = new InstrumentArticulation(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: InstrumentArticulation, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: InstrumentArticulation | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: InstrumentArticulation, json: any): void { + json.staffLine = obj.staffLine; + json.noteHeadDefault = obj.noteHeadDefault; + json.noteHeadHalf = obj.noteHeadHalf; + json.noteHeadWhole = obj.noteHeadWhole; + json.techniqueSymbol = obj.techniqueSymbol; + json.techniqueSymbolPlacement = obj.techniqueSymbolPlacement; + json.outputMidiNumber = obj.outputMidiNumber; + } + public static setProperty(obj: InstrumentArticulation, property: string, value: any): boolean { + switch (property) { + case "staffline": + obj.staffLine = value; + return true; + case "noteheaddefault": + obj.noteHeadDefault = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + return true; + case "noteheadhalf": + obj.noteHeadHalf = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + return true; + case "noteheadwhole": + obj.noteHeadWhole = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + return true; + case "techniquesymbol": + obj.techniqueSymbol = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + return true; + case "techniquesymbolplacement": + obj.techniqueSymbolPlacement = isNaN(parseInt(value)) ? TextBaseline[Object.keys(TextBaseline).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TextBaseline] : parseInt(value); + return true; + case "outputmidinumber": + obj.outputMidiNumber = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts new file mode 100644 index 000000000..8a3adf225 --- /dev/null +++ b/src/generated/model/MasterBarSerializer.ts @@ -0,0 +1,157 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { MasterBar } from "@src/model/MasterBar"; +import { SectionSerializer } from "@src/generated/model/SectionSerializer"; +import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; +import { FermataSerializer } from "@src/generated/model/FermataSerializer"; +import { KeySignature } from "@src/model/KeySignature"; +import { KeySignatureType } from "@src/model/KeySignatureType"; +import { TripletFeel } from "@src/model/TripletFeel"; +import { Section } from "@src/model/Section"; +import { Automation } from "@src/model/Automation"; +import { Fermata } from "@src/model/Fermata"; +export class MasterBarSerializer { + public static fromJson(json: any): MasterBar { + const obj = new MasterBar(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: MasterBar, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: MasterBar | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: MasterBar, json: any): void { + json.alternateEndings = obj.alternateEndings; + json.index = obj.index; + json.keySignature = obj.keySignature; + json.keySignatureType = obj.keySignatureType; + json.isDoubleBar = obj.isDoubleBar; + json.isRepeatStart = obj.isRepeatStart; + json.repeatCount = obj.repeatCount; + json.timeSignatureNumerator = obj.timeSignatureNumerator; + json.timeSignatureDenominator = obj.timeSignatureDenominator; + json.timeSignatureCommon = obj.timeSignatureCommon; + json.tripletFeel = obj.tripletFeel; + if (json.section) { + if (obj.section) { + SectionSerializer.fillToJson(obj.section, json.section); + } + } + else { + json.section = SectionSerializer.toJson(obj.section); + } + if (json.tempoAutomation) { + if (obj.tempoAutomation) { + AutomationSerializer.fillToJson(obj.tempoAutomation, json.tempoAutomation); + } + } + else { + json.tempoAutomation = AutomationSerializer.toJson(obj.tempoAutomation); + } + json.fermata = ({} as any); + obj.fermata.forEach(($mv, $mk) => { (json.fermata as any)[$mk] = FermataSerializer.toJson($mv); }); + json.start = obj.start; + json.isAnacrusis = obj.isAnacrusis; + } + public static setProperty(obj: MasterBar, property: string, value: any): boolean { + switch (property) { + case "alternateendings": + obj.alternateEndings = value; + return true; + case "index": + obj.index = value; + return true; + case "keysignature": + obj.keySignature = isNaN(parseInt(value)) ? KeySignature[Object.keys(KeySignature).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof KeySignature] : parseInt(value); + return true; + case "keysignaturetype": + obj.keySignatureType = isNaN(parseInt(value)) ? KeySignatureType[Object.keys(KeySignatureType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof KeySignatureType] : parseInt(value); + return true; + case "isdoublebar": + obj.isDoubleBar = value; + return true; + case "isrepeatstart": + obj.isRepeatStart = value; + return true; + case "repeatcount": + obj.repeatCount = value; + return true; + case "timesignaturenumerator": + obj.timeSignatureNumerator = value; + return true; + case "timesignaturedenominator": + obj.timeSignatureDenominator = value; + return true; + case "timesignaturecommon": + obj.timeSignatureCommon = value; + return true; + case "tripletfeel": + obj.tripletFeel = isNaN(parseInt(value)) ? TripletFeel[Object.keys(TripletFeel).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TripletFeel] : parseInt(value); + return true; + case "fermata": + obj.fermata = new Map(); + for (let $mk in value) + if (value.hasOwnProperty($mk)) + obj.fermata.set(parseInt($mk), FermataSerializer.fromJson(value[$mk])); + return true; + case "start": + obj.start = value; + return true; + case "isanacrusis": + obj.isAnacrusis = value; + return true; + } + if (["section"].indexOf(property) >= 0) { + if (obj.section) + SectionSerializer.fillFromJson(obj.section, value); + else + obj.section = value ? SectionSerializer.fromJson(value) : null; + return true; + } + else { + for (const $c of ["section"]) + if (property.indexOf($c) === 0) { + if (!obj.section) { + obj.section = new Section(); + } + if (SectionSerializer.setProperty(obj.section, property.substring($c.length), value)) { + return true; + } + } + } + if (["tempoautomation"].indexOf(property) >= 0) { + if (obj.tempoAutomation) + AutomationSerializer.fillFromJson(obj.tempoAutomation, value); + else + obj.tempoAutomation = value ? AutomationSerializer.fromJson(value) : null; + return true; + } + else { + for (const $c of ["tempoautomation"]) + if (property.indexOf($c) === 0) { + if (!obj.tempoAutomation) { + obj.tempoAutomation = new Automation(); + } + if (AutomationSerializer.setProperty(obj.tempoAutomation, property.substring($c.length), value)) { + return true; + } + } + } + return false; + } +} + diff --git a/src/generated/model/NoteCloner.ts b/src/generated/model/NoteCloner.ts new file mode 100644 index 000000000..ed4f90a0d --- /dev/null +++ b/src/generated/model/NoteCloner.ts @@ -0,0 +1,59 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Note } from "@src/model/Note"; +import { BendPointCloner } from "./BendPointCloner"; +export class NoteCloner { + public static clone(original: Note): Note { + const clone = new Note(); + clone.index = original.index; + clone.accentuated = original.accentuated; + clone.bendType = original.bendType; + clone.bendStyle = original.bendStyle; + clone.isContinuedBend = original.isContinuedBend; + clone.bendPoints = []; + for (const i of original.bendPoints) { + clone.addBendPoint(BendPointCloner.clone(i)); + } + clone.fret = original.fret; + clone.string = original.string; + clone.octave = original.octave; + clone.tone = original.tone; + clone.percussionArticulation = original.percussionArticulation; + clone.isVisible = original.isVisible; + clone.isLeftHandTapped = original.isLeftHandTapped; + clone.isHammerPullOrigin = original.isHammerPullOrigin; + clone.hammerPullOriginNoteId = original.hammerPullOriginNoteId; + clone.hammerPullDestinationNoteId = original.hammerPullDestinationNoteId; + clone.isSlurDestination = original.isSlurDestination; + clone.slurOriginNoteId = original.slurOriginNoteId; + clone.slurDestinationNoteId = original.slurDestinationNoteId; + clone.harmonicType = original.harmonicType; + clone.harmonicValue = original.harmonicValue; + clone.isGhost = original.isGhost; + clone.isLetRing = original.isLetRing; + clone.isPalmMute = original.isPalmMute; + clone.isDead = original.isDead; + clone.isStaccato = original.isStaccato; + clone.slideInType = original.slideInType; + clone.slideOutType = original.slideOutType; + clone.vibrato = original.vibrato; + clone.tieOriginNoteId = original.tieOriginNoteId; + clone.tieDestinationNoteId = original.tieDestinationNoteId; + clone.isTieDestination = original.isTieDestination; + clone.leftHandFinger = original.leftHandFinger; + clone.rightHandFinger = original.rightHandFinger; + clone.isFingering = original.isFingering; + clone.trillValue = original.trillValue; + clone.trillSpeed = original.trillSpeed; + clone.durationPercent = original.durationPercent; + clone.accidentalMode = original.accidentalMode; + clone.dynamics = original.dynamics; + clone.isEffectSlurOrigin = original.isEffectSlurOrigin; + clone.hasEffectSlur = original.hasEffectSlur; + return clone; + } +} + diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts new file mode 100644 index 000000000..9866d7b36 --- /dev/null +++ b/src/generated/model/NoteSerializer.ts @@ -0,0 +1,222 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Note } from "@src/model/Note"; +import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; +import { AccentuationType } from "@src/model/AccentuationType"; +import { BendType } from "@src/model/BendType"; +import { BendStyle } from "@src/model/BendStyle"; +import { HarmonicType } from "@src/model/HarmonicType"; +import { SlideInType } from "@src/model/SlideInType"; +import { SlideOutType } from "@src/model/SlideOutType"; +import { VibratoType } from "@src/model/VibratoType"; +import { Fingers } from "@src/model/Fingers"; +import { Duration } from "@src/model/Duration"; +import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; +import { DynamicValue } from "@src/model/DynamicValue"; +export class NoteSerializer { + public static fromJson(json: any): Note { + const obj = new Note(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Note, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Note | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Note, json: any): void { + json.id = obj.id; + json.index = obj.index; + json.accentuated = obj.accentuated; + json.bendType = obj.bendType; + json.bendStyle = obj.bendStyle; + json.isContinuedBend = obj.isContinuedBend; + json.bendPoints = obj.bendPoints.map($li => BendPointSerializer.toJson($li)); + json.fret = obj.fret; + json.string = obj.string; + json.octave = obj.octave; + json.tone = obj.tone; + json.percussionArticulation = obj.percussionArticulation; + json.isVisible = obj.isVisible; + json.isLeftHandTapped = obj.isLeftHandTapped; + json.isHammerPullOrigin = obj.isHammerPullOrigin; + json.hammerPullOriginNoteId = obj.hammerPullOriginNoteId; + json.hammerPullDestinationNoteId = obj.hammerPullDestinationNoteId; + json.isSlurDestination = obj.isSlurDestination; + json.slurOriginNoteId = obj.slurOriginNoteId; + json.slurDestinationNoteId = obj.slurDestinationNoteId; + json.harmonicType = obj.harmonicType; + json.harmonicValue = obj.harmonicValue; + json.isGhost = obj.isGhost; + json.isLetRing = obj.isLetRing; + json.isPalmMute = obj.isPalmMute; + json.isDead = obj.isDead; + json.isStaccato = obj.isStaccato; + json.slideInType = obj.slideInType; + json.slideOutType = obj.slideOutType; + json.vibrato = obj.vibrato; + json.tieOriginNoteId = obj.tieOriginNoteId; + json.tieDestinationNoteId = obj.tieDestinationNoteId; + json.isTieDestination = obj.isTieDestination; + json.leftHandFinger = obj.leftHandFinger; + json.rightHandFinger = obj.rightHandFinger; + json.isFingering = obj.isFingering; + json.trillValue = obj.trillValue; + json.trillSpeed = obj.trillSpeed; + json.durationPercent = obj.durationPercent; + json.accidentalMode = obj.accidentalMode; + json.dynamics = obj.dynamics; + json.isEffectSlurOrigin = obj.isEffectSlurOrigin; + json.hasEffectSlur = obj.hasEffectSlur; + } + public static setProperty(obj: Note, property: string, value: any): boolean { + switch (property) { + case "id": + obj.id = value; + return true; + case "index": + obj.index = value; + return true; + case "accentuated": + obj.accentuated = isNaN(parseInt(value)) ? AccentuationType[Object.keys(AccentuationType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof AccentuationType] : parseInt(value); + return true; + case "bendtype": + obj.bendType = isNaN(parseInt(value)) ? BendType[Object.keys(BendType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendType] : parseInt(value); + return true; + case "bendstyle": + obj.bendStyle = isNaN(parseInt(value)) ? BendStyle[Object.keys(BendStyle).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendStyle] : parseInt(value); + return true; + case "iscontinuedbend": + obj.isContinuedBend = value; + return true; + case "bendpoints": + obj.bendPoints = []; + for (const $li of value) + obj.bendPoints.push(BendPointSerializer.fromJson($li)); + return true; + case "fret": + obj.fret = value; + return true; + case "string": + obj.string = value; + return true; + case "octave": + obj.octave = value; + return true; + case "tone": + obj.tone = value; + return true; + case "percussionarticulation": + obj.percussionArticulation = value; + return true; + case "isvisible": + obj.isVisible = value; + return true; + case "islefthandtapped": + obj.isLeftHandTapped = value; + return true; + case "ishammerpullorigin": + obj.isHammerPullOrigin = value; + return true; + case "hammerpulloriginnoteid": + obj.hammerPullOriginNoteId = value; + return true; + case "hammerpulldestinationnoteid": + obj.hammerPullDestinationNoteId = value; + return true; + case "isslurdestination": + obj.isSlurDestination = value; + return true; + case "sluroriginnoteid": + obj.slurOriginNoteId = value; + return true; + case "slurdestinationnoteid": + obj.slurDestinationNoteId = value; + return true; + case "harmonictype": + obj.harmonicType = isNaN(parseInt(value)) ? HarmonicType[Object.keys(HarmonicType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof HarmonicType] : parseInt(value); + return true; + case "harmonicvalue": + obj.harmonicValue = value; + return true; + case "isghost": + obj.isGhost = value; + return true; + case "isletring": + obj.isLetRing = value; + return true; + case "ispalmmute": + obj.isPalmMute = value; + return true; + case "isdead": + obj.isDead = value; + return true; + case "isstaccato": + obj.isStaccato = value; + return true; + case "slideintype": + obj.slideInType = isNaN(parseInt(value)) ? SlideInType[Object.keys(SlideInType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SlideInType] : parseInt(value); + return true; + case "slideouttype": + obj.slideOutType = isNaN(parseInt(value)) ? SlideOutType[Object.keys(SlideOutType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SlideOutType] : parseInt(value); + return true; + case "vibrato": + obj.vibrato = isNaN(parseInt(value)) ? VibratoType[Object.keys(VibratoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof VibratoType] : parseInt(value); + return true; + case "tieoriginnoteid": + obj.tieOriginNoteId = value; + return true; + case "tiedestinationnoteid": + obj.tieDestinationNoteId = value; + return true; + case "istiedestination": + obj.isTieDestination = value; + return true; + case "lefthandfinger": + obj.leftHandFinger = isNaN(parseInt(value)) ? Fingers[Object.keys(Fingers).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Fingers] : parseInt(value); + return true; + case "righthandfinger": + obj.rightHandFinger = isNaN(parseInt(value)) ? Fingers[Object.keys(Fingers).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Fingers] : parseInt(value); + return true; + case "isfingering": + obj.isFingering = value; + return true; + case "trillvalue": + obj.trillValue = value; + return true; + case "trillspeed": + obj.trillSpeed = isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + return true; + case "durationpercent": + obj.durationPercent = value; + return true; + case "accidentalmode": + obj.accidentalMode = isNaN(parseInt(value)) ? NoteAccidentalMode[Object.keys(NoteAccidentalMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof NoteAccidentalMode] : parseInt(value); + return true; + case "dynamics": + obj.dynamics = isNaN(parseInt(value)) ? DynamicValue[Object.keys(DynamicValue).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof DynamicValue] : parseInt(value); + return true; + case "iseffectslurorigin": + obj.isEffectSlurOrigin = value; + return true; + case "haseffectslur": + obj.hasEffectSlur = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts new file mode 100644 index 000000000..a1af96c03 --- /dev/null +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -0,0 +1,68 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { PlaybackInformation } from "@src/model/PlaybackInformation"; +export class PlaybackInformationSerializer { + public static fromJson(json: any): PlaybackInformation { + const obj = new PlaybackInformation(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: PlaybackInformation, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: PlaybackInformation | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: PlaybackInformation, json: any): void { + json.volume = obj.volume; + json.balance = obj.balance; + json.port = obj.port; + json.program = obj.program; + json.primaryChannel = obj.primaryChannel; + json.secondaryChannel = obj.secondaryChannel; + json.isMute = obj.isMute; + json.isSolo = obj.isSolo; + } + public static setProperty(obj: PlaybackInformation, property: string, value: any): boolean { + switch (property) { + case "volume": + obj.volume = value; + return true; + case "balance": + obj.balance = value; + return true; + case "port": + obj.port = value; + return true; + case "program": + obj.program = value; + return true; + case "primarychannel": + obj.primaryChannel = value; + return true; + case "secondarychannel": + obj.secondaryChannel = value; + return true; + case "ismute": + obj.isMute = value; + return true; + case "issolo": + obj.isSolo = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts new file mode 100644 index 000000000..d74865d1f --- /dev/null +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -0,0 +1,40 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { RenderStylesheet } from "@src/model/RenderStylesheet"; +export class RenderStylesheetSerializer { + public static fromJson(json: any): RenderStylesheet { + const obj = new RenderStylesheet(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: RenderStylesheet, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: RenderStylesheet | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: RenderStylesheet, json: any): void { + json.hideDynamics = obj.hideDynamics; + } + public static setProperty(obj: RenderStylesheet, property: string, value: any): boolean { + switch (property) { + case "hidedynamics": + obj.hideDynamics = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts new file mode 100644 index 000000000..2201536cf --- /dev/null +++ b/src/generated/model/ScoreSerializer.ts @@ -0,0 +1,124 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Score } from "@src/model/Score"; +import { MasterBarSerializer } from "@src/generated/model/MasterBarSerializer"; +import { TrackSerializer } from "@src/generated/model/TrackSerializer"; +import { RenderStylesheetSerializer } from "@src/generated/model/RenderStylesheetSerializer"; +import { RenderStylesheet } from "@src/model/RenderStylesheet"; +export class ScoreSerializer { + public static fromJson(json: any): Score { + const obj = new Score(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Score, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Score | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Score, json: any): void { + json.album = obj.album; + json.artist = obj.artist; + json.copyright = obj.copyright; + json.instructions = obj.instructions; + json.music = obj.music; + json.notices = obj.notices; + json.subTitle = obj.subTitle; + json.title = obj.title; + json.words = obj.words; + json.tab = obj.tab; + json.tempo = obj.tempo; + json.tempoLabel = obj.tempoLabel; + json.masterBars = obj.masterBars.map($li => MasterBarSerializer.toJson($li)); + json.tracks = obj.tracks.map($li => TrackSerializer.toJson($li)); + if (json.stylesheet) { + RenderStylesheetSerializer.fillToJson(obj.stylesheet, json.stylesheet); + } + else { + json.stylesheet = (RenderStylesheetSerializer.toJson(obj.stylesheet)!); + } + } + public static setProperty(obj: Score, property: string, value: any): boolean { + switch (property) { + case "album": + obj.album = value; + return true; + case "artist": + obj.artist = value; + return true; + case "copyright": + obj.copyright = value; + return true; + case "instructions": + obj.instructions = value; + return true; + case "music": + obj.music = value; + return true; + case "notices": + obj.notices = value; + return true; + case "subtitle": + obj.subTitle = value; + return true; + case "title": + obj.title = value; + return true; + case "words": + obj.words = value; + return true; + case "tab": + obj.tab = value; + return true; + case "tempo": + obj.tempo = value; + return true; + case "tempolabel": + obj.tempoLabel = value; + return true; + case "masterbars": + obj.masterBars = []; + for (const $li of value) + obj.addMasterBar(MasterBarSerializer.fromJson($li)); + return true; + case "tracks": + obj.tracks = []; + for (const $li of value) + obj.addTrack(TrackSerializer.fromJson($li)); + return true; + } + if (["stylesheet"].indexOf(property) >= 0) { + if (obj.stylesheet) + RenderStylesheetSerializer.fillFromJson(obj.stylesheet, value); + else + obj.stylesheet = RenderStylesheetSerializer.fromJson(value); + return true; + } + else { + for (const $c of ["stylesheet"]) + if (property.indexOf($c) === 0) { + if (!obj.stylesheet) { + obj.stylesheet = new RenderStylesheet(); + } + if (RenderStylesheetSerializer.setProperty(obj.stylesheet, property.substring($c.length), value)) { + return true; + } + } + } + return false; + } +} + diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts new file mode 100644 index 000000000..2b7e39b65 --- /dev/null +++ b/src/generated/model/SectionSerializer.ts @@ -0,0 +1,44 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Section } from "@src/model/Section"; +export class SectionSerializer { + public static fromJson(json: any): Section { + const obj = new Section(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Section, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Section | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Section, json: any): void { + json.marker = obj.marker; + json.text = obj.text; + } + public static setProperty(obj: Section, property: string, value: any): boolean { + switch (property) { + case "marker": + obj.marker = value; + return true; + case "text": + obj.text = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts new file mode 100644 index 000000000..3be601a9d --- /dev/null +++ b/src/generated/model/StaffSerializer.ts @@ -0,0 +1,93 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Staff } from "@src/model/Staff"; +import { BarSerializer } from "@src/generated/model/BarSerializer"; +import { ChordSerializer } from "@src/generated/model/ChordSerializer"; +import { Chord } from "@src/model/Chord"; +export class StaffSerializer { + public static fromJson(json: any): Staff { + const obj = new Staff(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Staff, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Staff | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Staff, json: any): void { + json.index = obj.index; + json.bars = obj.bars.map($li => BarSerializer.toJson($li)); + json.chords = ({} as any); + obj.chords.forEach(($mv, $mk) => { (json.chords as any)[$mk] = ChordSerializer.toJson($mv); }); + json.capo = obj.capo; + json.transpositionPitch = obj.transpositionPitch; + json.displayTranspositionPitch = obj.displayTranspositionPitch; + json.tuning = obj.tuning.slice(); + json.tuningName = obj.tuningName; + json.showTablature = obj.showTablature; + json.showStandardNotation = obj.showStandardNotation; + json.isPercussion = obj.isPercussion; + json.standardNotationLineCount = obj.standardNotationLineCount; + } + public static setProperty(obj: Staff, property: string, value: any): boolean { + switch (property) { + case "index": + obj.index = value; + return true; + case "bars": + obj.bars = []; + for (const $li of value) + obj.addBar(BarSerializer.fromJson($li)); + return true; + case "chords": + obj.chords = new Map(); + for (let $mk in value) + if (value.hasOwnProperty($mk)) + obj.addChord($mk, ChordSerializer.fromJson(value[$mk])); + return true; + case "capo": + obj.capo = value; + return true; + case "transpositionpitch": + obj.transpositionPitch = value; + return true; + case "displaytranspositionpitch": + obj.displayTranspositionPitch = value; + return true; + case "tuning": + obj.tuning = value.slice(); + return true; + case "tuningname": + obj.tuningName = value; + return true; + case "showtablature": + obj.showTablature = value; + return true; + case "showstandardnotation": + obj.showStandardNotation = value; + return true; + case "ispercussion": + obj.isPercussion = value; + return true; + case "standardnotationlinecount": + obj.standardNotationLineCount = value; + return true; + } + return false; + } +} + diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts new file mode 100644 index 000000000..e86a6d6f4 --- /dev/null +++ b/src/generated/model/TrackSerializer.ts @@ -0,0 +1,93 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Track } from "@src/model/Track"; +import { StaffSerializer } from "@src/generated/model/StaffSerializer"; +import { PlaybackInformationSerializer } from "@src/generated/model/PlaybackInformationSerializer"; +import { Color } from "@src/model/Color"; +import { InstrumentArticulationSerializer } from "@src/generated/model/InstrumentArticulationSerializer"; +import { PlaybackInformation } from "@src/model/PlaybackInformation"; +export class TrackSerializer { + public static fromJson(json: any): Track { + const obj = new Track(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Track, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Track | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Track, json: any): void { + json.index = obj.index; + json.staves = obj.staves.map($li => StaffSerializer.toJson($li)); + if (json.playbackInfo) { + PlaybackInformationSerializer.fillToJson(obj.playbackInfo, json.playbackInfo); + } + else { + json.playbackInfo = (PlaybackInformationSerializer.toJson(obj.playbackInfo)!); + } + json.color = (Color.toJson(obj.color)!); + json.name = obj.name; + json.shortName = obj.shortName; + json.percussionArticulations = obj.percussionArticulations.map($li => InstrumentArticulationSerializer.toJson($li)); + } + public static setProperty(obj: Track, property: string, value: any): boolean { + switch (property) { + case "index": + obj.index = value; + return true; + case "staves": + obj.staves = []; + for (const $li of value) + obj.addStaff(StaffSerializer.fromJson($li)); + return true; + case "color": + obj.color = (Color.fromJson(value)!); + return true; + case "name": + obj.name = value; + return true; + case "shortname": + obj.shortName = value; + return true; + case "percussionarticulations": + obj.percussionArticulations = []; + for (const $li of value) + obj.percussionArticulations.push(InstrumentArticulationSerializer.fromJson($li)); + return true; + } + if (["playbackinfo"].indexOf(property) >= 0) { + if (obj.playbackInfo) + PlaybackInformationSerializer.fillFromJson(obj.playbackInfo, value); + else + obj.playbackInfo = PlaybackInformationSerializer.fromJson(value); + return true; + } + else { + for (const $c of ["playbackinfo"]) + if (property.indexOf($c) === 0) { + if (!obj.playbackInfo) { + obj.playbackInfo = new PlaybackInformation(); + } + if (PlaybackInformationSerializer.setProperty(obj.playbackInfo, property.substring($c.length), value)) { + return true; + } + } + } + return false; + } +} + diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts new file mode 100644 index 000000000..a7888e7e6 --- /dev/null +++ b/src/generated/model/VoiceSerializer.ts @@ -0,0 +1,51 @@ +// +// This code was auto-generated. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +import { Voice } from "@src/model/Voice"; +import { BeatSerializer } from "@src/generated/model/BeatSerializer"; +export class VoiceSerializer { + public static fromJson(json: any): Voice { + const obj = new Voice(); + this.fillFromJson(obj, json); + return obj; + } + public static fillFromJson(obj: Voice, json: any): void { + if (json) { + for (const $k in json) { + this.setProperty(obj, $k.toLowerCase(), json[$k]); + } + } + } + public static toJson(obj: Voice | null): any { + if (!obj) { + return null; + } + const json: any = {}; + this.fillToJson(obj, json); + return json; + } + public static fillToJson(obj: Voice, json: any): void { + json.index = obj.index; + json.beats = obj.beats.map($li => BeatSerializer.toJson($li)); + json.isEmpty = obj.isEmpty; + } + public static setProperty(obj: Voice, property: string, value: any): boolean { + switch (property) { + case "index": + obj.index = value; + return true; + case "beats": + obj.beats = []; + for (const $li of value) + obj.addBeat(BeatSerializer.fromJson($li)); + return true; + case "isempty": + obj.isEmpty = value; + return true; + } + return false; + } +} + diff --git a/src/importer/AlphaTexImporter.ts b/src/importer/AlphaTexImporter.ts index 04da79585..da025f106 100644 --- a/src/importer/AlphaTexImporter.ts +++ b/src/importer/AlphaTexImporter.ts @@ -32,6 +32,7 @@ import { Voice } from '@src/model/Voice'; import { Logger } from '@src/Logger'; import { ModelUtils, TuningParseResult } from '@src/model/ModelUtils'; import { AlphaTabError, AlphaTabErrorType } from '@src/AlphaTabError'; +import { BeatCloner } from '@src/generated/model/BeatCloner'; /** * A list of terminals recognized by the alphaTex-parser @@ -1035,7 +1036,7 @@ export class AlphaTexImporter extends ScoreImporter { } this.beatEffects(beat); for (let i: number = 0; i < beatRepeat - 1; i++) { - voice.addBeat(beat.clone()); + voice.addBeat(BeatCloner.clone(beat)); } return true; } diff --git a/src/importer/GpifParser.ts b/src/importer/GpifParser.ts index 347923fe7..4068cb823 100644 --- a/src/importer/GpifParser.ts +++ b/src/importer/GpifParser.ts @@ -43,6 +43,8 @@ import { PercussionMapper } from '@src/model/PercussionMapper'; import { InstrumentArticulation } from '@src/model/InstrumentArticulation'; import { MusicFontSymbol } from '@src/model/MusicFontSymbol'; import { TextBaseline } from '@src/platform/ICanvas'; +import { BeatCloner } from '@src/generated/model/BeatCloner'; +import { NoteCloner } from '@src/generated/model/NoteCloner'; /** * This structure represents a duration within a gpif @@ -2066,7 +2068,7 @@ export class GpifParser { if (beatId !== GpifParser.InvalidId) { // important! we clone the beat because beats get reused // in gp6, our model needs to have unique beats. - let beat: Beat = this._beatById.get(beatId)!.clone(); + let beat: Beat = BeatCloner.clone(this._beatById.get(beatId)!); voice.addBeat(beat); let rhythmId: string = this._rhythmOfBeat.get(beatId)!; let rhythm: GpifRhythm = this._rhythmById.get(rhythmId)!; @@ -2079,7 +2081,7 @@ export class GpifParser { if (this._notesOfBeat.has(beatId)) { for (let noteId of this._notesOfBeat.get(beatId)!) { if (noteId !== GpifParser.InvalidId) { - const note = this._noteById.get(noteId)!.clone(); + const note = NoteCloner.clone(this._noteById.get(noteId)!); // reset midi value for non-percussion staves if (staff.isPercussion) { note.fret = -1; diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 1bbd1507d..bf83f6f90 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -21,6 +21,7 @@ import { NotationMode } from '@src/NotationSettings'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { BeamDirection } from '@src/rendering/utils/BeamDirection'; +import { BeatCloner } from '@src/generated/model/BeatCloner'; // TODO: TypeScript optimizes away (elides) some types if they are not used in any expression // the AST transformer reference is not respected so we add one manually @@ -128,6 +129,8 @@ export class Beat { /** * Gets or sets the fermata applied to this beat. + * @clone_ignore + * @json_ignore */ public fermata: Fermata | null = null; @@ -707,7 +710,7 @@ export class Beat { if (needCopyBeatForBend) { // if this beat is a simple bend convert it to a grace beat // and generate a placeholder beat with tied notes - let cloneBeat: Beat = this.clone(); + let cloneBeat: Beat = BeatCloner.clone(this); cloneBeat.id = Beat._globalBeatId++; cloneBeat.pickStroke = PickStroke.None; for (let i: number = 0, j: number = cloneBeat.notes.length; i < j; i++) { @@ -786,11 +789,6 @@ export class Beat { return null; } - public clone(): Beat { - // dynamically implemented via AST transformer - return new Beat(); - } - public chain() { for(const n of this.notes) { this.noteValueLookup.set(n.realValue, n); diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index c3629ce5a..e20ceb575 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -6,6 +6,7 @@ import { MidiFile } from '@src/midi/MidiFile'; import { Score } from '@src/model/Score'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; +import { ScoreSerializer } from '@src/generated/model/ScoreSerializer'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further @@ -35,7 +36,7 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - return Score.toJson(score); + return ScoreSerializer.toJson(score); } /** @@ -55,7 +56,7 @@ export class JsonConverter { * @returns The converted score object. */ public static jsObjectToScore(jsObject: any, settings?: Settings): Score { - let score: Score = Score.fromJson(jsObject); + let score: Score = ScoreSerializer.fromJson(jsObject); score.finish(settings ?? new Settings()); return score; } diff --git a/src/model/Note.ts b/src/model/Note.ts index 40dfdcc05..59d3583d7 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -63,6 +63,7 @@ export class Note { /** * Gets or sets the note from which this note continues the bend. * @clone_ignore + * @json_ignore */ public bendOrigin: Note | null = null; @@ -80,6 +81,7 @@ export class Note { /** * Gets or sets the bend point with the highest bend value. * @clone_ignore + * @json_ignore */ public maxBendPoint: BendPoint | null = null; @@ -342,6 +344,7 @@ export class Note { /** * Gets or sets the destination note for the let-ring effect. * @clone_ignore + * @json_ignore */ public letRingDestination: Note | null = null; @@ -353,6 +356,7 @@ export class Note { /** * Gets or sets the destination note for the palm-mute effect. * @clone_ignore + * @json_ignore */ public palmMuteDestination: Note | null = null; @@ -379,12 +383,14 @@ export class Note { /** * Gets or sets the target note for several slide types. * @clone_ignore + * @json_ignore */ public slideTarget: Note | null = null; /** * Gets or sets the source note for several slide types. * @clone_ignore + * @json_ignore */ public slideOrigin: Note | null = null; @@ -492,11 +498,13 @@ export class Note { /** * @clone_ignore + * @json_ignore */ public effectSlurOrigin: Note | null = null; /** * @clone_ignore + * @json_ignore */ public effectSlurDestination: Note | null = null; @@ -971,9 +979,4 @@ export class Note { } } } - - public clone(): Note { - // dynamically implemented via AST transformer - return new Note(); - } } diff --git a/src/model/Score.ts b/src/model/Score.ts index 91567200c..2f392d4b3 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -152,20 +152,4 @@ export class Score { ? this._noteByIdLookup.get(noteId)! : null; } - - /** - * @target web - */ - public static fromJson(json: any): Score { - // dynamically implemented via AST transformer - return new Score(); - } - - /** - * @target web - */ - public static toJson(score: Score): unknown { - // dynamically implemented via AST transformer - return null; - } } diff --git a/src/model/Section.ts b/src/model/Section.ts index f5bf888ab..cc1fb3821 100644 --- a/src/model/Section.ts +++ b/src/model/Section.ts @@ -1,6 +1,7 @@ /** * This public class is used to describe the beginning of a * section within a song. It acts like a marker. + * @json */ export class Section { /** diff --git a/src/platform/javascript/AlphaTabWebWorker.ts b/src/platform/javascript/AlphaTabWebWorker.ts index 610693321..b4a27381f 100644 --- a/src/platform/javascript/AlphaTabWebWorker.ts +++ b/src/platform/javascript/AlphaTabWebWorker.ts @@ -6,6 +6,7 @@ import { ScoreRenderer } from '@src/rendering/ScoreRenderer'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { Environment } from '@src/Environment'; +import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * @target web @@ -29,7 +30,7 @@ export class AlphaTabWebWorker { switch (cmd) { case 'alphaTab.initialize': let settings: Settings = new Settings(); - settings.fillFromJson(data.settings); + SettingsSerializer.fillFromJson(settings, data.settings); Logger.logLevel = settings.core.logLevel; this._renderer = new ScoreRenderer(settings); this._renderer.partialRenderFinished.on(result => { @@ -90,7 +91,7 @@ export class AlphaTabWebWorker { } private updateSettings(json: unknown): void { - this._renderer.settings.fillFromJson(json); + SettingsSerializer.fillFromJson(this._renderer.settings, json); } private renderMultiple(score: Score, trackIndexes: number[]): void { diff --git a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts index 77cd6f784..433ec8da9 100644 --- a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts +++ b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts @@ -8,6 +8,7 @@ import { RenderFinishedEventArgs } from '@src/rendering/RenderFinishedEventArgs' import { BoundsLookup } from '@src/rendering/utils/BoundsLookup'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; +import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * @target web @@ -59,7 +60,7 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { } private serializeSettingsForWorker(settings: Settings): unknown { - let json: any = Settings.toJson(settings); + let json: any = SettingsSerializer.toJson(settings); // cut out player settings, they are only needed on UI thread side json.player = null; return json; diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index 161bb571a..5db944f80 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -23,6 +23,7 @@ import { AlphaTabApi } from '@src/platform/javascript/AlphaTabApi'; import { AlphaTabWorkerScoreRenderer } from '@src/platform/javascript/AlphaTabWorkerScoreRenderer'; import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; import { Cursors } from '@src/platform/Cursors'; +import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * @target web @@ -122,7 +123,7 @@ export class BrowserUiFacade implements IUiFacade { settings = raw; } else { settings = new Settings(); - settings.fillFromJson(raw); + SettingsSerializer.fillFromJson(settings, raw); } let dataAttributes: Map = this.getDataAttributes(); diff --git a/tsconfig.base.json b/tsconfig.base.json index 4c5c1c7c1..166ae76ee 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -26,21 +26,16 @@ "baseUrl": ".", "paths": { "@src/*": [ - "src/*" + "src/*", ] }, "typeRoots": [ "types", "node_modules/@types" - ], - "plugins": [ - { - "transform": "./src.compiler/AlphaTabTransformations.ts" - } ] }, "include": [ - "src" + "src", ], "exclude": [ "**/node_modules", diff --git a/tsconfig.build-csharp.json b/tsconfig.build-csharp.json index 71c1ec600..d8d6f5fc8 100644 --- a/tsconfig.build-csharp.json +++ b/tsconfig.build-csharp.json @@ -15,7 +15,7 @@ "paths": { "@src*": [ - "src*" + "src*", ], "@test*": [ "test*" diff --git a/tsconfig.json b/tsconfig.json index 46a31f0ed..c43fcf86a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "declarationDir": "dist/types.test", "paths": { "@src*": [ - "src*" + "src*", ], "@test*": [ "test*" From e0805d615bc1d6e622f96c071df13f7275e46c7d Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 19 Dec 2020 14:29:50 +0100 Subject: [PATCH 07/19] Generate TS during compilation --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 8032bda04..b3f569802 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,13 @@ "scripts": { "clean": "rimraf dist", "lint": "tslint --project tsconfig.build.json -t codeFrame 'src/**/*.ts' 'test/**/*.ts'", - "build": "tsc --project tsconfig.build.json && rollup -c rollup.config.js", + "build": "npm run generate-typescript && tsc --project tsconfig.build.json && rollup -c rollup.config.js", "build-ci": "npm run clean && npm run build && npm pack", "start": "node scripts/setup-playground.js && npm run build && concurrently --kill-others \"tsc --project tsconfig.build.json --watch\" \"rollup -c rollup.config.js -w\"", - "test": "tsc --project tsconfig.json && concurrently --kill-others \"tsc --project tsconfig.json -w\" \"karma start karma.conf.js --browsers Chrome --no-single-run --reporters spec,kjhtml\"", - "test-ci": "tsc --project tsconfig.json && karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters spec", + "test": "npm run generate-typescript && tsc --project tsconfig.json && concurrently --kill-others \"tsc --project tsconfig.json -w\" \"karma start karma.conf.js --browsers Chrome --no-single-run --reporters spec,kjhtml\"", + "test-ci": "npm run generate-typescript && tsc --project tsconfig.json && karma start karma.conf.js --browsers ChromeHeadless --single-run --reporters spec", "generate-typescript": "rimraf src/generated && ts-node --project tsconfig.build-csharp.json src.compiler/typescript/AlphaTabGenerator.ts --project tsconfig.build-csharp.json", - "generate-csharp": "ts-node --project tsconfig.build-csharp.json src.compiler/csharp/CSharpTranspiler.ts --project tsconfig.build-csharp.json", + "generate-csharp": "npm run generate-typescript && ts-node --project tsconfig.build-csharp.json src.compiler/csharp/CSharpTranspiler.ts --project tsconfig.build-csharp.json", "build-csharp": "npm run generate-csharp && cd src.csharp && dotnet build -c Release", "build-csharp-ci": "npm run clean && npm run generate-csharp && cd src.csharp && dotnet build -c Release", "test-csharp": "cd src.csharp && dotnet test", From 82c1dddb7b553ef5d5a627e2a23af308d251cd44 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 19 Dec 2020 22:23:12 +0100 Subject: [PATCH 08/19] WIP JsonReader/Writer --- src.compiler/BuilderHelpers.ts | 2 +- src.compiler/TranspilerBase.ts | 87 +- src.compiler/csharp/CSharpAst.ts | 5 + src.compiler/csharp/CSharpAstPrinter.ts | 12 + src.compiler/csharp/CSharpAstTransformer.ts | 93 +- src.compiler/csharp/CSharpEmitter.ts | 9 +- src.compiler/csharp/CSharpEmitterContext.ts | 26 +- src.compiler/csharp/CSharpTranspiler.ts | 2 +- src.compiler/typescript/EmitterBase.ts | 2 +- src.compiler/typescript/SerializerEmitter.ts | 1181 ++++++++--------- src.csharp/AlphaTab/Core/TypeHelper.cs | 8 +- src/CoreSettings.ts | 1 + src/DisplaySettings.ts | 1 + src/PlayerSettings.ts | 2 + src/Settings.ts | 15 +- src/generated/CoreSettingsSerializer.ts | 87 +- src/generated/DisplaySettingsSerializer.ts | 102 +- src/generated/ImporterSettingsSerializer.ts | 43 +- src/generated/NotationSettingsSerializer.ts | 95 +- src/generated/PlayerSettingsSerializer.ts | 93 +- src/generated/RenderingResourcesSerializer.ts | 84 +- src/generated/SettingsSerializer.ts | 112 +- .../SlidePlaybackSettingsSerializer.ts | 48 +- .../VibratoPlaybackSettingsSerializer.ts | 73 +- src/generated/model/AutomationSerializer.ts | 58 +- src/generated/model/BarSerializer.ts | 69 +- src/generated/model/BeatSerializer.ts | 256 ++-- src/generated/model/BendPointSerializer.ts | 43 +- src/generated/model/ChordSerializer.ts | 68 +- src/generated/model/FermataSerializer.ts | 43 +- .../model/InstrumentArticulationSerializer.ts | 68 +- src/generated/model/MasterBarSerializer.ts | 178 ++- src/generated/model/NoteSerializer.ts | 254 ++-- .../model/PlaybackInformationSerializer.ts | 73 +- .../model/RenderStylesheetSerializer.ts | 38 +- src/generated/model/ScoreSerializer.ts | 138 +- src/generated/model/SectionSerializer.ts | 43 +- src/generated/model/StaffSerializer.ts | 106 +- src/generated/model/TrackSerializer.ts | 96 +- src/generated/model/VoiceSerializer.ts | 54 +- src/io/IJsonReader.ts | 34 + src/io/IJsonWriter.ts | 27 + src/model/Bar.ts | 4 - src/model/Beat.ts | 7 - src/model/Color.ts | 6 - src/model/Font.ts | 6 - src/model/MasterBar.ts | 4 - src/model/Note.ts | 4 - src/model/Score.ts | 6 - src/model/Staff.ts | 5 - src/model/Track.ts | 4 - src/model/Voice.ts | 4 - src/util/JsonHelper.ts | 8 + 53 files changed, 2076 insertions(+), 1811 deletions(-) create mode 100644 src/io/IJsonReader.ts create mode 100644 src/io/IJsonWriter.ts create mode 100644 src/util/JsonHelper.ts diff --git a/src.compiler/BuilderHelpers.ts b/src.compiler/BuilderHelpers.ts index afafa6b74..bda0c358d 100644 --- a/src.compiler/BuilderHelpers.ts +++ b/src.compiler/BuilderHelpers.ts @@ -108,7 +108,7 @@ export function wrapToNonNull(isNullableType: boolean, expr: ts.Expression, fact } export function isTypedArray(type: ts.Type) { - return !!type.symbol.members?.has(ts.escapeLeadingUnderscores('slice')); + return !!type.symbol?.members?.has(ts.escapeLeadingUnderscores('slice')); } export function hasFlag(type: ts.Type, flag: ts.TypeFlags): boolean { diff --git a/src.compiler/TranspilerBase.ts b/src.compiler/TranspilerBase.ts index afaab9ad1..25b4fd2b2 100644 --- a/src.compiler/TranspilerBase.ts +++ b/src.compiler/TranspilerBase.ts @@ -1,32 +1,43 @@ import * as ts from 'typescript'; -export default function (emit: (program: ts.Program) => void) { - function createDiagnosticReporter(pretty?: boolean): ts.DiagnosticReporter { - const host: ts.FormatDiagnosticsHost = { - getCurrentDirectory: () => ts.sys.getCurrentDirectory(), - getNewLine: () => ts.sys.newLine, - getCanonicalFileName: ts.sys.useCaseSensitiveFileNames - ? x => x - : x => x.toLowerCase(), - }; - - if (!pretty) { - return diagnostic => ts.sys.write(ts.formatDiagnostic(diagnostic, host)); - } +function createDiagnosticReporter(pretty?: boolean): ts.DiagnosticReporter { + const host: ts.FormatDiagnosticsHost = { + getCurrentDirectory: () => ts.sys.getCurrentDirectory(), + getNewLine: () => ts.sys.newLine, + getCanonicalFileName: ts.sys.useCaseSensitiveFileNames + ? x => x + : x => x.toLowerCase(), + }; - return diagnostic => { - ts.sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine()); - }; + if (!pretty) { + return diagnostic => ts.sys.write(ts.formatDiagnostic(diagnostic, host)); } + return diagnostic => { + ts.sys.write(ts.formatDiagnosticsWithColorAndContext([diagnostic], host) + host.getNewLine()); + }; +} + +export default function (emit: (program: ts.Program, diagnostics: ts.Diagnostic[]) => void, handleErrors: boolean = false) { const commandLine = ts.parseCommandLine(ts.sys.args); if (!ts.sys.fileExists(commandLine.options.project!)) { ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); } + let reportDiagnostic = createDiagnosticReporter(); + const parseConfigFileHost: ts.ParseConfigFileHost = ts.sys; + parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = diagnostic => { + reportDiagnostic(diagnostic); + ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); + }; const parsedCommandLine = ts.getParsedCommandLineOfConfigFile(commandLine.options.project!, commandLine.options, parseConfigFileHost, /*extendedConfigCache*/ undefined, commandLine.watchOptions)!; + const pretty = !!ts.sys.writeOutputIsTTY && ts.sys.writeOutputIsTTY(); + if (pretty) { + reportDiagnostic = createDiagnosticReporter(true); + } + const program = ts.createProgram({ rootNames: parsedCommandLine.fileNames, options: parsedCommandLine.options, @@ -34,7 +45,47 @@ export default function (emit: (program: ts.Program) => void) { host: ts.createCompilerHost(parsedCommandLine.options), }); + const allDiagnostics = program.getConfigFileParsingDiagnostics().slice(); + const configFileParsingDiagnosticsLength = allDiagnostics.length; + allDiagnostics.push(...program.getSyntacticDiagnostics()); + + if (allDiagnostics.length === configFileParsingDiagnosticsLength) { + allDiagnostics.push(...program.getOptionsDiagnostics()); + allDiagnostics.push(...program.getGlobalDiagnostics()); + allDiagnostics.push(...program.getSemanticDiagnostics()); + } + program.getTypeChecker(); - - emit(program); + + emit(program, allDiagnostics); + + if (handleErrors) { + let diagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); + let errorCount = 0; + let warningCount = 0; + diagnostics.forEach(d => { + switch (d.category) { + case ts.DiagnosticCategory.Error: errorCount++; break; + case ts.DiagnosticCategory.Warning: warningCount++; break; + } + reportDiagnostic(d); + }); + + if (pretty) { + reportDiagnostic({ + file: undefined, + start: undefined, + length: undefined, + code: 6194, + messageText: `Compilation completed with ${errorCount} errors and ${warningCount} warnings${ts.sys.newLine}`, + category: errorCount > 0 ? ts.DiagnosticCategory.Error : warningCount > 0 ? ts.DiagnosticCategory.Warning : ts.DiagnosticCategory.Message, + }); + } + + if (errorCount > 0) { + ts.sys.exit(ts.ExitStatus.DiagnosticsPresent_OutputsGenerated); + } else { + ts.sys.exit(ts.ExitStatus.Success); + } + } } \ No newline at end of file diff --git a/src.compiler/csharp/CSharpAst.ts b/src.compiler/csharp/CSharpAst.ts index 7a2ab3c25..e3719d2e4 100644 --- a/src.compiler/csharp/CSharpAst.ts +++ b/src.compiler/csharp/CSharpAst.ts @@ -75,6 +75,7 @@ export enum SyntaxKind { Identifier, DefaultExpression, ToDoExpression, + TypeOfExpression, Attribute } @@ -380,6 +381,10 @@ export interface NonNullExpression extends Node { expression: Expression; } +export interface TypeOfExpression extends Node { + expression: Expression; +} + export interface NullSafeExpression extends Node { expression: Expression; } diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index 54b58c598..8b47fdecc 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -741,6 +741,9 @@ export default class CSharpAstPrinter { case cs.SyntaxKind.DefaultExpression: this.writeDefaultExpression(expr as cs.DefaultExpression); break; + case cs.SyntaxKind.TypeOfExpression: + this.writeTypeOfExpression(expr as cs.TypeOfExpression); + break; default: throw new Error(`Unhandled expression type: ${cs.SyntaxKind[expr.nodeType]}`); } @@ -754,6 +757,15 @@ export default class CSharpAstPrinter { } } + private writeTypeOfExpression(expr: cs.TypeOfExpression) { + this.write('typeof'); + if (expr.expression) { + this.write('('); + this.writeExpression(expr.expression); + this.write(')'); + } + } + private writePrefixUnaryExpression(expr: cs.PrefixUnaryExpression) { this.write(expr.operator); this.writeExpression(expr.operand); diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index c5fd35ecb..8fa819b3b 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -2017,13 +2017,27 @@ export default class CSharpAstTransformer { } private visitThisExpression(parent: cs.Node, expression: ts.ThisExpression) { - const csExpr = { - parent: parent, - tsNode: expression, - nodeType: cs.SyntaxKind.ThisLiteral - } as cs.ThisLiteral; + if (parent.nodeType === cs.SyntaxKind.MemberAccessExpression && + parent.tsSymbol && + this._context.isStaticSymbol(parent.tsSymbol)) { + const identifier = { + parent: parent, + tsNode: expression, + tsSymbol: this._context.typeChecker.getSymbolAtLocation(expression), + nodeType: cs.SyntaxKind.Identifier, + text: parent.tsSymbol.name + } as cs.Identifier; - return csExpr; + return identifier; + } else { + const csExpr = { + parent: parent, + tsNode: expression, + nodeType: cs.SyntaxKind.ThisLiteral + } as cs.ThisLiteral; + + return csExpr; + } } private visitSuperLiteralExpression(parent: cs.Node, expression: ts.SuperExpression) { @@ -2788,25 +2802,35 @@ export default class CSharpAstTransformer { return null; } - const csArg = { - expression: {} as cs.Expression, - nodeType: cs.SyntaxKind.CastExpression, - parent: parent, - tsNode: expression.argumentExpression, - type: { - nodeType: cs.SyntaxKind.PrimitiveTypeNode, - type: cs.PrimitiveType.Int - } as cs.PrimitiveTypeNode - } as cs.CastExpression; - elementAccess.argumentExpression = csArg; + let type = symbol ? this._context.typeChecker.getTypeOfSymbolAtLocation(symbol!, expression.expression) : null; + if(type) { + type = this._context.typeChecker.getNonNullableType(type); + } + const isArrayAccessor = !symbol || (type && type.symbol && !!type.symbol.members?.has(ts.escapeLeadingUnderscores('slice'))); + if (isArrayAccessor) { + const csArg = { + expression: {} as cs.Expression, + nodeType: cs.SyntaxKind.CastExpression, + parent: parent, + tsNode: expression.argumentExpression, + type: { + nodeType: cs.SyntaxKind.PrimitiveTypeNode, + type: cs.PrimitiveType.Int + } as cs.PrimitiveTypeNode + } as cs.CastExpression; + elementAccess.argumentExpression = csArg; - const par = { - nodeType: cs.SyntaxKind.ParenthesizedExpression, - parent: csArg, - expression: argumentExpression - } as cs.ParenthesizedExpression; - argumentExpression.parent = par; - csArg.expression = par; + const par = { + nodeType: cs.SyntaxKind.ParenthesizedExpression, + parent: csArg, + expression: argumentExpression + } as cs.ParenthesizedExpression; + argumentExpression.parent = par; + csArg.expression = par; + } else { + elementAccess.argumentExpression = argumentExpression; + argumentExpression.parent = elementAccess; + } return this.wrapToSmartCast(parent, elementAccess, expression); } @@ -3004,6 +3028,7 @@ export default class CSharpAstTransformer { nodeType: cs.SyntaxKind.NullLiteral } as cs.NullLiteral; } + const identifier = { parent: parent, tsNode: expression, @@ -3012,6 +3037,26 @@ export default class CSharpAstTransformer { text: expression.text } as cs.Identifier; + if (identifier.tsSymbol) { + switch (expression.parent.kind) { + case ts.SyntaxKind.PropertyAccessExpression: + case ts.SyntaxKind.BinaryExpression: + break; + default: + switch(identifier.tsSymbol.flags) { + case ts.SymbolFlags.Alias: + return { + parent: parent, + nodeType: cs.SyntaxKind.TypeOfExpression, + tsNode: expression, + expression: identifier + } as cs.TypeOfExpression; + } + break; + } + + } + return this.wrapToSmartCast(parent, identifier, expression); } diff --git a/src.compiler/csharp/CSharpEmitter.ts b/src.compiler/csharp/CSharpEmitter.ts index 9a64ce1c2..71f9c1f03 100644 --- a/src.compiler/csharp/CSharpEmitter.ts +++ b/src.compiler/csharp/CSharpEmitter.ts @@ -3,11 +3,10 @@ import CSharpAstTransformer from './CSharpAstTransformer'; import CSharpEmitterContext from './CSharpEmitterContext'; import CSharpAstPrinter from './CSharpAstPrinter'; -export default function emit(program: ts.Program): ts.Diagnostic[] { - const diagnostics: ts.Diagnostic[] = []; - +export default function emit(program: ts.Program, diagnostics:ts.Diagnostic[]) { const context = new CSharpEmitterContext(program); - sourceFiles.forEach(sourceFile => { + program.getRootFileNames().forEach(file => { + const sourceFile = program.getSourceFile(file)!; const transformer = new CSharpAstTransformer(sourceFile, context); transformer.transform(); }); @@ -24,6 +23,4 @@ export default function emit(program: ts.Program): ts.Diagnostic[] { } diagnostics.push(...context.diagnostics); - - return diagnostics; } \ No newline at end of file diff --git a/src.compiler/csharp/CSharpEmitterContext.ts b/src.compiler/csharp/CSharpEmitterContext.ts index 453bf2bf3..21e19a87b 100644 --- a/src.compiler/csharp/CSharpEmitterContext.ts +++ b/src.compiler/csharp/CSharpEmitterContext.ts @@ -5,12 +5,6 @@ import * as path from 'path'; type SymbolKey = string; export default class CSharpEmitterContext { - public isNullableString(type: ts.Type) { - if (type.isUnion()) { - type = this.typeChecker.getNonNullableType(type); - } - return ((type.flags & ts.TypeFlags.String) || (type.flags & ts.TypeFlags.StringLiteral)); - } private _fileLookup: Map = new Map(); private _symbolLookup: Map = new Map(); private _exportedSymbols: Map = new Map(); @@ -389,6 +383,10 @@ export default class CSharpEmitterContext { // typescript compiler API somehow does not provide proper type symbols // for function types, we need to attempt resolving the types via the function type declaration + if (!tsType.symbol || !tsType.symbol.declarations) { + return null; + } + let functionTypeNode: ts.FunctionTypeNode | null = null; for (const declaration of tsType.symbol.declarations) { if (ts.isFunctionTypeNode(declaration)) { @@ -810,7 +808,7 @@ export default class CSharpEmitterContext { public isBooleanSmartCast(tsNode: ts.Node) { let tsParent = tsNode.parent; - if(!tsParent) { + if (!tsParent) { return false; } @@ -1011,6 +1009,7 @@ export default class CSharpEmitterContext { if (contextualType.symbol) { switch (contextualType.symbol.name) { case 'ArrayLike': + case '__type': return true; } } @@ -1215,4 +1214,17 @@ export default class CSharpEmitterContext { break; } } + + public isStaticSymbol(tsSymbol: ts.Symbol) { + return !!tsSymbol.declarations.find(d => d.modifiers && + !!d.modifiers.find(m => m.kind === ts.SyntaxKind.StaticKeyword) + ); + } + + public isNullableString(type: ts.Type) { + if (type.isUnion()) { + type = this.typeChecker.getNonNullableType(type); + } + return ((type.flags & ts.TypeFlags.String) || (type.flags & ts.TypeFlags.StringLiteral)); + } } diff --git a/src.compiler/csharp/CSharpTranspiler.ts b/src.compiler/csharp/CSharpTranspiler.ts index 378259efd..9f890130e 100644 --- a/src.compiler/csharp/CSharpTranspiler.ts +++ b/src.compiler/csharp/CSharpTranspiler.ts @@ -1,4 +1,4 @@ import emit from './CSharpEmitter'; import transpiler from '../TranspilerBase' -transpiler(emit); \ No newline at end of file +transpiler(emit, true); \ No newline at end of file diff --git a/src.compiler/typescript/EmitterBase.ts b/src.compiler/typescript/EmitterBase.ts index 7f7316368..9d59f7fbf 100644 --- a/src.compiler/typescript/EmitterBase.ts +++ b/src.compiler/typescript/EmitterBase.ts @@ -93,7 +93,7 @@ export default function createEmitter(jsDocMarker: string, generate: (program: t }); } - return function emit(program: ts.Program) { + return function emit(program: ts.Program, _diagnostics: ts.Diagnostic[]) { program.getRootFileNames().forEach(file => { scanSourceFile(program, program.getSourceFile(file)!); }); diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index 2c3c505bd..fb1cf8fd0 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -8,6 +8,7 @@ import * as ts from 'typescript'; import createEmitter from './EmitterBase' import { addNewLines } from '../BuilderHelpers'; import { isPrimitiveType } from '../BuilderHelpers'; +import { hasFlag } from '../BuilderHelpers'; import { getTypeWithNullableInfo } from '../BuilderHelpers'; import { isTypedArray } from '../BuilderHelpers'; import { unwrapArrayItemType } from '../BuilderHelpers'; @@ -17,6 +18,7 @@ import { isNumberType } from '../BuilderHelpers'; import { wrapToNonNull } from '../BuilderHelpers'; interface JsonProperty { + partialNames: boolean; property: ts.PropertyDeclaration; jsonNames: string[]; } @@ -69,111 +71,58 @@ function findSerializerModule(type: ts.Type, options: ts.CompilerOptions) { } // -// FromJson -function generateFromJsonBody(input: ts.ClassDeclaration) { - const statements: ts.Statement[] = []; - // const obj = new Type(); - statements.push( - ts.factory.createVariableStatement( - undefined, - ts.factory.createVariableDeclarationList([ - ts.factory.createVariableDeclaration( - 'obj', - undefined, - undefined, - ts.factory.createNewExpression(ts.factory.createIdentifier(input.name!.text), [], []) - ) - ], ts.NodeFlags.Const) - ) - ); +// fromJson +function generateFromJsonBody() { + return ts.factory.createBlock(addNewLines([ + ts.factory.createIfStatement( + ts.factory.createBinaryExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'currentValueType'), + ts.SyntaxKind.ExclamationEqualsEqualsToken, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Object'), + ), + ts.factory.createBlock([ + ts.factory.createReturnStatement() + ]) + ), - // this.fillFromJson(obj, json); - statements.push( - ts.factory.createExpressionStatement( + ts.factory.createWhileStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'fillFromJson'), - [], - [ - ts.factory.createIdentifier('obj'), - ts.factory.createIdentifier('json'), - ] - ) - ) - ); - - // return obj; - statements.push( - // return json; - ts.factory.createReturnStatement(ts.factory.createIdentifier('obj')) - ); - - return ts.factory.createBlock(addNewLines(statements)); -} - -function createFromJsonMethod(input: ts.ClassDeclaration) { - return ts.factory.createMethodDeclaration( - undefined, - [ - ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), - ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), - ], - undefined, - 'fromJson', - undefined, - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextProperty'), undefined, - undefined, - 'json', - undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - undefined - ) - ], - ts.factory.createTypeReferenceNode( - input.name!.text, - undefined - ), - generateFromJsonBody(input) - ); -} - -// -// fillFromJson -function generateFillFromJsonBody() { - return ts.factory.createBlock(addNewLines([ - ts.factory.createIfStatement( - // if(json) for($k in json) { this.setProperty(obj, $k.toLowerCase(), json[$k]) } - ts.factory.createIdentifier('json'), + [] + ), ts.factory.createBlock([ - ts.factory.createForInStatement( - ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('$k')], ts.NodeFlags.Const), - ts.factory.createIdentifier('json'), - ts.factory.createBlock([ - ts.factory.createExpressionStatement( + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'setProperty'), + undefined, + [ + ts.factory.createIdentifier('obj'), ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'setProperty'), - [], - [ - // obj - ts.factory.createIdentifier('obj'), - // $k.toLowerCase(), - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$k'), 'toLowerCase'), [], []), - // json[$k] - ts.factory.createElementAccessExpression(ts.factory.createIdentifier('json'), ts.factory.createIdentifier('$k')) - ] - ) - ) - ]) + ts.factory.createPropertyAccessExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyName'), + undefined, + [] + ), + 'toLowerCase' + ), + undefined, + [] + ), + ts.factory.createIdentifier('reader'), + ] + ) ) ]) ) ])); } -function createFillFromJsonMethod(input: ts.ClassDeclaration) { +function createFromJsonMethod(input: ts.ClassDeclaration, + importer: (name: string, module: string) => void) { + importer('IJsonReader', '@src/io/IJsonReader'); + importer('JsonValueType', '@src/io/IJsonReader'); return ts.factory.createMethodDeclaration( undefined, [ @@ -181,7 +130,7 @@ function createFillFromJsonMethod(input: ts.ClassDeclaration) { ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) ], undefined, - 'fillFromJson', + 'fromJson', undefined, undefined, [ @@ -200,328 +149,288 @@ function createFillFromJsonMethod(input: ts.ClassDeclaration) { undefined, undefined, undefined, - 'json', + 'reader', undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.factory.createTypeReferenceNode('IJsonReader') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - generateFillFromJsonBody() + generateFromJsonBody() ) } // // toJson -function generateToJsonBody() { - return ts.factory.createBlock(addNewLines([ - // if(!obj) { return null; } - ts.factory.createIfStatement( - ts.factory.createPrefixUnaryExpression( - ts.SyntaxKind.ExclamationToken, - ts.factory.createIdentifier('obj') - ), - ts.factory.createBlock([ - ts.factory.createReturnStatement(ts.factory.createNull()) - ]) - ), +function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecker) { + if (!type) { + return null; + } - // const json:any = {}; - ts.factory.createVariableStatement( - undefined, - ts.factory.createVariableDeclarationList([ - ts.factory.createVariableDeclaration( - 'json', - undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - ts.factory.createObjectLiteralExpression() - ) - ], ts.NodeFlags.Const) - ), + const isArray = isTypedArray(type); + const arrayItemType = unwrapArrayItemType(type, typeChecker); - // this.fillToJson(obj, json) - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'fillToJson'), - [], - [ - ts.factory.createIdentifier('obj'), - ts.factory.createIdentifier('json') - ] - ) - ), + if (hasFlag(type, ts.TypeFlags.Number)) { + return "writeNumber"; + } + if (hasFlag(type, ts.TypeFlags.String)) { + return "writeString"; + } + if (hasFlag(type, ts.TypeFlags.Boolean)) { + return "writeBoolean"; + } - // return json; - ts.factory.createReturnStatement(ts.factory.createIdentifier('json')) - ])); -} + if (isEnumType(type)) { + return 'writeEnum'; + } -function createToJsonMethod(input: ts.ClassDeclaration) { - return ts.factory.createMethodDeclaration( - undefined, - [ - ts.factory.createModifier(ts.SyntaxKind.PublicKeyword), - ts.factory.createModifier(ts.SyntaxKind.StaticKeyword), - ], - undefined, - 'toJson', - undefined, - undefined, - [ - ts.factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'obj', - undefined, - ts.factory.createUnionTypeNode([ - ts.factory.createTypeReferenceNode( - input.name!.text, - undefined - ), - ts.factory.createLiteralTypeNode(ts.factory.createNull()) - ]), - undefined - ) - ], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), - generateToJsonBody() - ); + if (arrayItemType) { + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { + return "writeNumberArray"; + } + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { + return "writeStringArray"; + } + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { + return "writeBooleanArray"; + } + } else if (type.symbol) { + switch (type.symbol.name) { + case 'Uint8Array': + case 'Uint16Array': + case 'Uint32Array': + case 'Int8Array': + case 'Int16Array': + case 'Int32Array': + case 'Float32Array': + case 'Float64Array': + return 'write' + type.symbol.name; + } + } + + return null; } -// -// fillToJson -function generateFillToJsonBody( +function generateToJsonBody( program: ts.Program, propertiesToSerialize: JsonProperty[], importer: (name: string, module: string) => void) { const statements: ts.Statement[] = []; + statements.push(ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createIdentifier('obj') + ), + ts.factory.createBlock([ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeNull'), + undefined, [] + )), + ts.factory.createReturnStatement() + ]) + )) + + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartObject'), + undefined, [] + ))); + for (let prop of propertiesToSerialize) { const fieldName = (prop.property.name as ts.Identifier).text; const jsonName = prop.jsonNames.filter(n => n !== '')[0]; - const accessJsonName = function (): ts.Expression { - return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('json'), jsonName); - }; - const accessField = function (): ts.Expression { - return ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)); - }; + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writePropertyName'), + undefined, + [ + ts.factory.createStringLiteral(jsonName) + ] + ))); - const assignToJsonName = function (value: ts.Expression): ts.Statement { - return ts.factory.createExpressionStatement(ts.factory.createAssignment(accessJsonName(), value)); - }; + if (!jsonName) { + continue; + } + const typeChecker = program.getTypeChecker(); + const type = getTypeWithNullableInfo(typeChecker, prop.property.type!); + const isArray = isTypedArray(type.type!); - if (jsonName) { - const typeChecker = program.getTypeChecker(); - const type = getTypeWithNullableInfo(typeChecker, prop.property.type!); - if (isPrimitiveType(type.type!)) { - // json.jsonName = obj.fieldName - statements.push(assignToJsonName(accessField())); - } else if (isTypedArray(type.type!)) { - const arrayItemType = unwrapArrayItemType(type.type!, typeChecker); - if (!arrayItemType || isPrimitiveType(arrayItemType)) { - // json.jsonName = obj.fieldName ? obj.fieldName.slice() : null - if (type.isNullable) { - statements.push( - assignToJsonName( - ts.factory.createConditionalExpression( - accessField(), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'slice'), [], []), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createNull() - ) - ) - ); - } else { - statements.push( - assignToJsonName(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'slice'), [], [])) - ); - } - } else { - // json.jsonName = obj.fieldName ? obj.fieldName.map($li => TypeNameSerializer.toJson($li)) : null - let itemSerializer = arrayItemType.symbol.name + "Serializer"; - importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); - - const mapCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'map'), undefined, [ - ts.factory.createArrowFunction( - undefined, - undefined, - [ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$li')], - undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - undefined, - [ts.factory.createIdentifier('$li')] - ) - ), - ]); - if (type.isNullable) { - statements.push( - assignToJsonName( - ts.factory.createConditionalExpression( - accessField(), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - mapCall, - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createNull() - ) - ) - ); - } else { - statements.push( - assignToJsonName(mapCall) - ); - } - } - } else if (isMap(type.type)) { - const mapType = type.type as ts.TypeReference; - if (!isPrimitiveType(mapType.typeArguments![0])) { - throw new Error('only Map maps are supported extend if needed!'); - } - // json.jsonName = { } as any; - // this.fieldName.forEach((val, key) => (json.jsonName as any)[key] = val)) - statements.push( - assignToJsonName( - ts.factory.createAsExpression( - ts.factory.createObjectLiteralExpression(), - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ) - ) - ); + let writeValueMethodName: string | null = getWriteMethodNameForPrimitive(type.type!, typeChecker); - // json.jsonName = obj.fieldName ? obj.fieldName.map($li => TypeNameSerializer.toJson($li)) : null - let itemSerializer: string = ''; - if (!isPrimitiveType(mapType.typeArguments![1])) { - itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; - importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); - } + if (writeValueMethodName) { + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), writeValueMethodName), + undefined, + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ] + ))); + } else if (isArray) { + // NOTE: nullable Object arrays are not yet supported - const mapValue = isPrimitiveType(mapType.typeArguments![1]) - ? ts.factory.createIdentifier('$mv') - : ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - undefined, - [ts.factory.createIdentifier('$mv')] - ); + const arrayItemType = unwrapArrayItemType(type.type!, typeChecker)!; + + let itemSerializer = arrayItemType.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); + + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartArray'), + undefined, + [] + ))); - statements.push( + statements.push(ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration('i')], + ts.NodeFlags.Const + ), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createBlock([ ts.factory.createExpressionStatement( - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(accessField(), 'forEach'), undefined, [ - ts.factory.createArrowFunction( - undefined, - undefined, - [ - ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$mv'), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$mk') - ], - undefined, - ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.factory.createBlock([ - ts.factory.createExpressionStatement( - ts.factory.createAssignment( - ts.factory.createElementAccessExpression( - ts.factory.createAsExpression( - accessJsonName(), - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) - ), - ts.factory.createIdentifier('$mk') - ), - mapValue - ) - ) - ]) - ) - ]) - ) - ); - } else if (isImmutable(type.type)) { - let itemSerializer = type.type.symbol.name; - importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); - - // json.jsonName = TypeName.toJson(this.fieldName); - statements.push( - assignToJsonName( - wrapToNonNull( - type.isNullable, - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - [], - [accessField()] - ), - ts.factory + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + undefined, + [ + ts.factory.createIdentifier('i'), + ts.factory.createIdentifier('writer') + ] ) ) - ); + ]) + )); + + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndArray'), + undefined, + [] + ))); + } + else if (isMap(type.type)) { + const mapType = type.type as ts.TypeReference; + if (!isPrimitiveType(mapType.typeArguments![0])) { + throw new Error('only Map maps are supported extend if needed!'); + } + + let itemSerializer: string; + let writeValue: ts.Expression; + if (isPrimitiveType(mapType.typeArguments![1])) { + itemSerializer = ''; + writeValue = ts.factory.createIdentifier('v'); } else { - // not nullable: - // if(json.jsonName) { - // FieldSerializer.fillToJson(obj.fieldName, json.jsonName) - // } else { - // json.jsonName = FieldSerializer.toJson(obj.fieldName)!; - // } - - // nullable: - // if(json.jsonName) { - // if(obj.fieldName) FieldSerializer.fillToJson(obj.fieldName, json.jsonName) - // } else { - // json.jsonName = FieldSerializer.toJson(obj.fieldName); - // } - - let itemSerializer = type.type.symbol.name + "Serializer"; - importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); - - // this.field.fillToJson(json.jsonName) - let fillToJsonStatent: ts.Statement = ts.factory.createExpressionStatement( + itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); + writeValue = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + undefined, + [ts.factory.createIdentifier('m')] + ); + } + + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartObject'), + undefined, + [] + ))); + + statements.push( + ts.factory.createExpressionStatement( + ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) + , 'forEach'), undefined, [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v') + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock([ + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writePropertyName'), + undefined, + [ts.factory.createIdentifier('k')] + )), + ts.factory.createExpressionStatement(writeValue) + ]) + ) + ]) + ) + ); + + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndObject'), + undefined, + [] + ))); + + } else if (isImmutable(type.type)) { + let itemSerializer = type.type.symbol.name; + importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); + statements.push( + ts.factory.createExpressionStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fillToJson'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), [], [ - accessField(), - accessJsonName() + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createIdentifier('writer') ] ) - ); - if (type.isNullable) { - fillToJsonStatent = ts.factory.createIfStatement(accessField(), ts.factory.createBlock([fillToJsonStatent])); - } + ) + ); + } else { + if (!type.type.symbol) { + console.log('error'); + } + let itemSerializer = type.type.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); - statements.push( - ts.factory.createIfStatement( - // if(json.jsonName) - accessJsonName(), - // TypeSerializer.fillToJson(obj.fieldName, json.jsonName) - ts.factory.createBlock([fillToJsonStatent]), - // else json.jsonName = ... - ts.factory.createBlock([ - assignToJsonName( - wrapToNonNull( - type.isNullable, - ts.factory.createCallExpression( - // TypeName.toJson - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - [], - [accessField()] - ), - ts.factory - ), - ) - ]) - ) - ); + + const writeValue: ts.Statement = ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + [], + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createIdentifier('writer'), + ] + )); + + if (type.isNullable) { + statements.push(ts.factory.createIfStatement( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createBlock([ + writeValue + ]), + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeNull'), + undefined, + [] + )) + )); + } else { + statements.push(writeValue); } } } + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndObject'), + undefined, [] + ))); + return ts.factory.createBlock(addNewLines(statements)) } -function createFillToJsonMethod(program: ts.Program, +function createToJsonMethod(program: ts.Program, input: ts.ClassDeclaration, propertiesToSerialize: JsonProperty[], importer: (name: string, module: string) => void ) { + importer('IJsonWriter', '@src/io/IJsonWriter'); return ts.factory.createMethodDeclaration( undefined, [ @@ -529,7 +438,7 @@ function createFillToJsonMethod(program: ts.Program, ts.factory.createModifier(ts.SyntaxKind.StaticKeyword) ], undefined, - 'fillToJson', + 'toJson', undefined, undefined, [ @@ -539,84 +448,87 @@ function createFillToJsonMethod(program: ts.Program, undefined, 'obj', undefined, - ts.factory.createTypeReferenceNode( - input.name!.text, - undefined - ), + ts.factory.createUnionTypeNode([ + ts.factory.createTypeReferenceNode( + input.name!.text, + undefined + ), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]) ), ts.factory.createParameterDeclaration( undefined, undefined, undefined, - 'json', + 'writer', undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.factory.createTypeReferenceNode('IJsonWriter') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - generateFillToJsonBody(program, propertiesToSerialize, importer) + generateToJsonBody(program, propertiesToSerialize, importer) ) } // // setProperty -function createEnumMapping(value: string, type: ts.Type): ts.Expression { - // isNan(parseInt(value)) ? Enum[Object.keys(Enum).find($k => $k.toLowerCase() === value.toLowerCase()] : parseInt(value) - return ts.factory.createConditionalExpression( - ts.factory.createCallExpression(ts.factory.createIdentifier('isNaN'), undefined, [ - ts.factory.createCallExpression(ts.factory.createIdentifier('parseInt'), undefined, [ts.factory.createIdentifier(value)]) - ]), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createElementAccessExpression( - ts.factory.createIdentifier(type.symbol.name), - ts.factory.createAsExpression( - ts.factory.createCallExpression( - // Object.keys(EnumName).find - ts.factory.createPropertyAccessExpression( - // Object.keys(EnumName) - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), 'keys'), - [], - [ts.factory.createIdentifier(type.symbol.name)] - ), - 'find' - ), - [], - [ - ts.factory.createArrowFunction( - [], - [], - [ts.factory.createParameterDeclaration(undefined, undefined, undefined, '$k')], - undefined, - ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.factory.createBinaryExpression( - ts.factory.createCallExpression( - // $.toLowerCase() - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$k'), 'toLowerCase'), - [], - [] - ), - // === - ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken), - // value.toLowerCase() - ts.factory.createCallExpression( - // $.toLowerCase() - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(value), 'toLowerCase'), - [], - [] - ) - ) - ) - ] - ), - ts.factory.createTypeOperatorNode( - ts.SyntaxKind.KeyOfKeyword, - ts.factory.createTypeQueryNode(ts.factory.createIdentifier(type.symbol.name)) - ) - ) + +function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecker) { + if (!type) { + return null; + } + + const isArray = isTypedArray(type); + const arrayItemType = unwrapArrayItemType(type, typeChecker); + + if (hasFlag(type, ts.TypeFlags.Number)) { + return "readNumber"; + } + if (hasFlag(type, ts.TypeFlags.String)) { + return "readString"; + } + if (hasFlag(type, ts.TypeFlags.Boolean)) { + return "readBoolean"; + } + + if (arrayItemType) { + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { + return "readNumberArray"; + } + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { + return "readStringArray"; + } + if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { + return "readBooleanArray"; + } + } else if (type.symbol) { + switch (type.symbol.name) { + case 'Uint8Array': + case 'Uint16Array': + case 'Uint32Array': + case 'Int8Array': + case 'Int16Array': + case 'Int32Array': + case 'Float32Array': + case 'Float64Array': + return 'read' + type.symbol.name; + } + } + + return null; + +} + +function createEnumMapping(type: ts.Type): ts.Expression { + return ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('reader'), + 'readEnum' ), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createCallExpression(ts.factory.createIdentifier('parseInt'), undefined, [ts.factory.createIdentifier(value)]) + [ts.factory.createTypeReferenceNode(type.symbol.name)], + [ + ts.factory.createIdentifier(type.symbol.name) + ] ); } @@ -643,130 +555,104 @@ function generateSetPropertyBody(program: ts.Program, ); }; - if (isEnumType(type.type)) { - // obj.fieldName = enummapping - // return true; - importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())) + const primitiveRead = getReadMethodNameForPrimitive(type.type!, typeChecker); + if (primitiveRead) { + const read = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('reader'), + getReadMethodNameForPrimitive(type.type!, typeChecker)! + ), + undefined, + [] + ); if (type.isNullable) { - caseStatements.push(assignField( - ts.factory.createConditionalExpression( - ts.factory.createBinaryExpression( - ts.factory.createIdentifier('value'), - ts.SyntaxKind.EqualsEqualsEqualsToken, - ts.factory.createNull() - ), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createNull(), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - createEnumMapping('value', type.type) - ) - )); + caseStatements.push(assignField(read)); } else { - caseStatements.push(assignField(createEnumMapping('value', type.type))); + caseStatements.push(assignField(ts.factory.createNonNullExpression(read))); } caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); - } else if (isPrimitiveType(type.type)) { - // obj.fieldName = value + } else if (isEnumType(type.type)) { + // obj.fieldName = enummapping // return true; - caseStatements.push(assignField(ts.factory.createIdentifier('value'))); + importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())); + const read = createEnumMapping(type.type); + if (type.isNullable) { + caseStatements.push(assignField(read)); + } else { + caseStatements.push(assignField(ts.factory.createNonNullExpression(read))); + } caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isTypedArray(type.type!)) { - const arrayItemType = unwrapArrayItemType(type.type!, typeChecker); - if (!arrayItemType || isPrimitiveType(arrayItemType)) { - // nullable: - // obj.fieldName = value ? value.slice() : null - // return true; - - // not nullable: - // obj.fieldName = value.slice() - // return true; - const sliceCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('value'), 'slice'), [], []); - if (type.isNullable) { - caseStatements.push( - assignField( - ts.factory.createConditionalExpression( - ts.factory.createIdentifier('value'), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - sliceCall, - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createNull() - ) - ) - ); - } else { - caseStatements.push( - assignField(sliceCall) - ); - } - caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); - } else { - const collectionAddMethod = ts.getJSDocTags(prop.property) - .filter(t => t.tagName.text === 'json_add') - .map(t => t.comment ?? "")[0]; - - // obj.fieldName = []; - // for(const $li of value) { - // obj.addFieldName(Type.FromJson($li)); - // } - // or - // for(const $li of value) { - // obj.fieldName.push(Type.FromJson($li)); - // } - - let itemSerializer = arrayItemType.symbol.name + "Serializer"; - importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); - - const itemFromJson = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), - [], - [ts.factory.createIdentifier('$li')] - ); + const arrayItemType = unwrapArrayItemType(type.type!, typeChecker)!; + const collectionAddMethod = ts.getJSDocTags(prop.property) + .filter(t => t.tagName.text === 'json_add') + .map(t => t.comment ?? "")[0]; - const loopItems = [ - assignField(ts.factory.createArrayLiteralExpression(undefined)), - ts.factory.createForOfStatement( - undefined, - ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration('$li')], - ts.NodeFlags.Const - ), - ts.factory.createIdentifier('value'), - ts.factory.createExpressionStatement( - collectionAddMethod - // obj.addFieldName(ItemTypeSerializer.FromJson($li)) - ? ts.factory.createCallExpression( + // obj.fieldName = []; + // for(const i of value) { + // obj.addFieldName(Type.FromJson(i)); + // } + // or + // for(const __li of value) { + // obj.fieldName.push(Type.FromJson(__li)); + // } + + let itemSerializer = arrayItemType.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); + + const itemFromJson = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ + ts.factory.createIdentifier('i'), + ts.factory.createIdentifier('j') + ] + ); + + const loopItems = [ + assignField(ts.factory.createArrayLiteralExpression(undefined)), + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ts.factory.createVariableDeclaration('__li')], + ts.NodeFlags.Const + ), + ts.factory.createIdentifier('value'), + ts.factory.createExpressionStatement( + collectionAddMethod + // obj.addFieldName(ItemTypeSerializer.FromJson(__li)) + ? ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('obj'), + collectionAddMethod + ), + undefined, + [itemFromJson] + ) + // obj.fieldName.push(ItemTypeSerializer.FromJson(__li)) + : ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier('obj'), - collectionAddMethod - ), - undefined, - [itemFromJson] - ) - // obj.fieldName.push(ItemTypeSerializer.FromJson($li)) - : ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('obj'), - fieldName - ), - 'push' + fieldName ), - undefined, - [itemFromJson] - ) - ) - )]; - - if (type.isNullable) { - caseStatements.push(ts.factory.createIfStatement( - ts.factory.createIdentifier('value'), - ts.factory.createBlock(loopItems) - )); - } else { - caseStatements.push(...loopItems); - } - caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); + 'push' + ), + undefined, + [itemFromJson] + ) + ) + )]; + + if (type.isNullable) { + caseStatements.push(ts.factory.createIfStatement( + ts.factory.createIdentifier('value'), + ts.factory.createBlock(loopItems) + )); + } else { + caseStatements.push(...loopItems); } + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isMap(type.type)) { // this.fieldName = new Map(); @@ -785,20 +671,20 @@ function generateSetPropertyBody(program: ts.Program, } const mapKey = isEnumType(mapType.typeArguments![0]) - ? createEnumMapping('$mk', mapType.typeArguments![0]) + ? createEnumMapping(mapType.typeArguments![0]) : isNumberType(mapType.typeArguments![0]) ? ts.factory.createCallExpression( ts.factory.createIdentifier('parseInt'), undefined, - [ts.factory.createIdentifier('$mk')] + [ts.factory.createIdentifier('__mk')] ) - : ts.factory.createIdentifier('$mk'); + : ts.factory.createIdentifier('__mk'); if (isEnumType(mapType.typeArguments![0])) { importer(mapType.typeArguments![0].symbol!.name, findModule(mapType.typeArguments![0], program.getCompilerOptions())); } - let mapValue: ts.Expression = ts.factory.createElementAccessExpression(ts.factory.createIdentifier('value'), ts.factory.createIdentifier('$mk')); + let mapValue: ts.Expression = ts.factory.createElementAccessExpression(ts.factory.createIdentifier('value'), ts.factory.createIdentifier('__mk')); let itemSerializer: string = ''; if (!isPrimitiveType(mapType.typeArguments![1])) { itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; @@ -823,7 +709,7 @@ function generateSetPropertyBody(program: ts.Program, caseStatements.push( ts.factory.createForInStatement( ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration(ts.factory.createIdentifier('$mk'), undefined, undefined)], + [ts.factory.createVariableDeclaration(ts.factory.createIdentifier('__mk'), undefined, undefined)], ts.NodeFlags.Let ), ts.factory.createIdentifier('value'), @@ -831,7 +717,7 @@ function generateSetPropertyBody(program: ts.Program, ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('value'), 'hasOwnProperty'), undefined, - [ts.factory.createIdentifier('$mk')] + [ts.factory.createIdentifier('__mk')] ), ts.factory.createExpressionStatement( ts.factory.createCallExpression( @@ -881,8 +767,11 @@ function generateSetPropertyBody(program: ts.Program, let itemSerializer = type.type.symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); - importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())); + if (type.isNullable) { + importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())); + } + // TODO if no partial name support, simply generate cases statements.push( ts.factory.createIfStatement( // if(["", "core"].indexOf(property) >= 0) @@ -895,120 +784,115 @@ function generateSetPropertyBody(program: ts.Program, ts.SyntaxKind.GreaterThanEqualsToken, ts.factory.createNumericLiteral('0') ), - ts.factory.createBlock([ - // if(obj.field) { - // TypeNameSerializer.fillFromJson(obj.field, value); - // } else { - // obj.field = TypeNameSerializer.fromJson(value); - // or - // obj.field = value ? TypeNameSerializer.fromJson(value) : null; - // } - // return true; - ts.factory.createIfStatement( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier(itemSerializer), - 'fillFromJson' - ), - [], - [ - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('obj'), - fieldName - ), - ts.factory.createIdentifier('value') - ] - ) - ), - assignField( - type.isNullable - ? ts.factory.createConditionalExpression( - ts.factory.createIdentifier('value'), - ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createCallExpression( - // TypeName.fromJson - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), - [], - [ - ts.factory.createIdentifier('value') - ] - ), - ts.factory.createToken(ts.SyntaxKind.ColonToken), - ts.factory.createNull() - ) - : ts.factory.createCallExpression( + ts.factory.createBlock( + !type.isNullable + ? [ + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( // TypeName.fromJson ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), [], [ - ts.factory.createIdentifier('value') + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createIdentifier('reader') ] ) - ) - ), - ts.factory.createReturnStatement(ts.factory.createTrue()) - ]), - ts.factory.createBlock([ - // for(const candidate of ["", "core"]) { - // if(candidate.indexOf(property) === 0) { - // if(!this.field) { this.field = new FieldType(); } - // if(this.field.setProperty(property.substring(candidate.length), value)) return true; - // } - // } - ts.factory.createForOfStatement( - undefined, - ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('$c')], ts.NodeFlags.Const), - jsonNameArray, - ts.factory.createIfStatement( - ts.factory.createBinaryExpression( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('property'), 'indexOf'), - [], - [ts.factory.createIdentifier('$c')] + ), + ts.factory.createReturnStatement(ts.factory.createTrue()) + ] + : [ + ts.factory.createIfStatement( + ts.factory.createBinaryExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'currentValueType'), + ts.SyntaxKind.ExclamationEqualsEqualsToken, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Null'), ), - ts.SyntaxKind.EqualsEqualsEqualsToken, - ts.factory.createNumericLiteral('0') + ts.factory.createBlock([ + assignField(ts.factory.createNewExpression( + ts.factory.createIdentifier(type.type.symbol.name), + undefined, + [] + )), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + // TypeName.fromJson + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + [], + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createIdentifier('reader') + ] + ) + ) + ]), + ts.factory.createBlock([ + assignField(ts.factory.createNull()) + ]) ), + ts.factory.createReturnStatement(ts.factory.createTrue()) + ]), + !prop.partialNames ? undefined : + ts.factory.createBlock([ + // for(const candidate of ["", "core"]) { + // if(candidate.indexOf(property) === 0) { + // if(!this.field) { this.field = new FieldType(); } + // if(this.field.setProperty(property.substring(candidate.length), value)) return true; + // } + // } + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('c')], ts.NodeFlags.Const), + jsonNameArray, ts.factory.createBlock([ ts.factory.createIfStatement( - ts.factory.createPrefixUnaryExpression( - ts.SyntaxKind.ExclamationToken, - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) + ts.factory.createBinaryExpression( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('property'), 'indexOf'), + [], + [ts.factory.createIdentifier('c')] + ), + ts.SyntaxKind.EqualsEqualsEqualsToken, + ts.factory.createNumericLiteral('0') ), ts.factory.createBlock([ - assignField(ts.factory.createNewExpression(ts.factory.createIdentifier(type.type!.symbol!.name), [], [])) - ]) - ), - ts.factory.createIfStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier(itemSerializer), - 'setProperty' + type.isNullable && ts.factory.createIfStatement( + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) + ), + ts.factory.createBlock([ + assignField(ts.factory.createNewExpression(ts.factory.createIdentifier(type.type!.symbol!.name), [], [])) + ]) ), - [], - [ - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createIfStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('property'), - 'substring' + ts.factory.createIdentifier(itemSerializer), + 'setProperty' ), [], - [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('$c'), 'length')] + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('property'), + 'substring' + ), + [], + [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('c'), 'length')] + ), + ts.factory.createIdentifier('reader') + ] ), - ts.factory.createIdentifier('value') - ] - ), - ts.factory.createBlock([ - ts.factory.createReturnStatement(ts.factory.createTrue()) - ]) + ts.factory.createBlock([ + ts.factory.createReturnStatement(ts.factory.createTrue()) + ]) + ) + ].filter(s => !!s) as ts.Statement[]) ) ]) ) - ) - ]) + ]) ) ); } @@ -1073,9 +957,9 @@ function createSetPropertyMethod( undefined, undefined, undefined, - 'value', + 'reader', undefined, - ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ts.factory.createTypeReferenceNode('IJsonReader') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), @@ -1107,7 +991,8 @@ export default createEmitter('json', (program, input) => { if (!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_ignore')) { propertiesToSerialize.push({ property: propertyDeclaration, - jsonNames: jsonNames + jsonNames: jsonNames, + partialNames: !!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_partial_names') }); } } @@ -1146,10 +1031,8 @@ export default createEmitter('json', (program, input) => { undefined, undefined, [ - createFromJsonMethod(input), - createFillFromJsonMethod(input), - createToJsonMethod(input), - createFillToJsonMethod(program, input, propertiesToSerialize, importer), + createFromJsonMethod(input, importer), + createToJsonMethod(program, input, propertiesToSerialize, importer), createSetPropertyMethod(program, input, propertiesToSerialize, importer) ] )); diff --git a/src.csharp/AlphaTab/Core/TypeHelper.cs b/src.csharp/AlphaTab/Core/TypeHelper.cs index 8a8741286..42a7fcab5 100644 --- a/src.csharp/AlphaTab/Core/TypeHelper.cs +++ b/src.csharp/AlphaTab/Core/TypeHelper.cs @@ -185,7 +185,7 @@ public static int CharCodeAt(this string s, double index) { return s[(int) index]; } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string CharAt(this string s, double index) { @@ -252,5 +252,11 @@ public static bool IsTruthy(double s) { return !double.IsNaN(s) && s != 0; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IList Map(this IList source, Func func) + { + return source.Select(func).ToList(); + } } } diff --git a/src/CoreSettings.ts b/src/CoreSettings.ts index a9aa106d8..8699de9d8 100644 --- a/src/CoreSettings.ts +++ b/src/CoreSettings.ts @@ -33,6 +33,7 @@ export class CoreSettings { /** * Gets or sets the initial tracks that should be loaded for the score. * @target web + * @json_ignore */ public tracks: unknown = null; diff --git a/src/DisplaySettings.ts b/src/DisplaySettings.ts index ff645b69f..9211c1ff5 100644 --- a/src/DisplaySettings.ts +++ b/src/DisplaySettings.ts @@ -88,6 +88,7 @@ export class DisplaySettings { /** * Gets or sets the resources used during rendering. This defines all fonts and colors used. + * @json_partial_names */ public resources: RenderingResources = new RenderingResources(); diff --git a/src/PlayerSettings.ts b/src/PlayerSettings.ts index 7851d250a..f7bf0fb49 100644 --- a/src/PlayerSettings.ts +++ b/src/PlayerSettings.ts @@ -153,11 +153,13 @@ export class PlayerSettings { /** * Gets or sets the settings on how the vibrato audio is generated. + * @json_partial_names */ public readonly vibrato: VibratoPlaybackSettings = new VibratoPlaybackSettings(); /** * Gets or sets the setitngs on how the slide audio is generated. + * @json_partial_names */ public readonly slide: SlidePlaybackSettings = new SlidePlaybackSettings(); diff --git a/src/Settings.ts b/src/Settings.ts index 41480db3b..f17b3ea09 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -23,29 +23,34 @@ export class Settings { * The core settings control the general behavior of alphatab like * what modules are active. * @json_on_parent + * @json_partial_names */ - public readonly core: CoreSettings = new CoreSettings(); + public core: CoreSettings = new CoreSettings(); /** * The display settings control how the general layout and display of alphaTab is done. * @json_on_parent + * @json_partial_names */ - public readonly display: DisplaySettings = new DisplaySettings(); + public display: DisplaySettings = new DisplaySettings(); /** * The notation settings control how various music notation elements are shown and behaving. + * @json_partial_names */ - public readonly notation: NotationSettings = new NotationSettings(); + public notation: NotationSettings = new NotationSettings(); /** * All settings related to importers that decode file formats. + * @json_partial_names */ - public readonly importer: ImporterSettings = new ImporterSettings(); + public importer: ImporterSettings = new ImporterSettings(); /** * Contains all player related settings + * @json_partial_names */ - public readonly player: PlayerSettings = new PlayerSettings(); + public player: PlayerSettings = new PlayerSettings(); public setSongBookModeSettings(): void { this.notation.notationMode = NotationMode.SongBook; diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index 9a621873a..727869f7f 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -4,75 +4,78 @@ // the code is regenerated. // import { CoreSettings } from "@src/CoreSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { LogLevel } from "@src/LogLevel"; export class CoreSettingsSerializer { - public static fromJson(json: any): CoreSettings { - const obj = new CoreSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: CoreSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: CoreSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: CoreSettings | null): any { + public static toJson(obj: CoreSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; + writer.writeStartObject(); + writer.writePropertyName("scriptFile"); + writer.writeString(obj.scriptFile); + writer.writePropertyName("fontDirectory"); + writer.writeString(obj.fontDirectory); + writer.writePropertyName("file"); + writer.writeString(obj.file); + writer.writePropertyName("tex"); + writer.writeBoolean(obj.tex); + writer.writePropertyName("visibilityCheckInterval"); + writer.writeNumber(obj.visibilityCheckInterval); + writer.writePropertyName("enableLazyLoading"); + writer.writeBoolean(obj.enableLazyLoading); + writer.writePropertyName("engine"); + writer.writeString(obj.engine); + writer.writePropertyName("logLevel"); + writer.writeEnum(obj.logLevel); + writer.writePropertyName("useWorkers"); + writer.writeBoolean(obj.useWorkers); + writer.writePropertyName("includeNoteBounds"); + writer.writeBoolean(obj.includeNoteBounds); + writer.writeEndObject(); } - public static fillToJson(obj: CoreSettings, json: any): void { - json.scriptFile = obj.scriptFile; - json.fontDirectory = obj.fontDirectory; - json.file = obj.file; - json.tex = obj.tex; - json.tracks = obj.tracks; - json.visibilityCheckInterval = obj.visibilityCheckInterval; - json.enableLazyLoading = obj.enableLazyLoading; - json.engine = obj.engine; - json.logLevel = obj.logLevel; - json.useWorkers = obj.useWorkers; - json.includeNoteBounds = obj.includeNoteBounds; - } - public static setProperty(obj: CoreSettings, property: string, value: any): boolean { + public static setProperty(obj: CoreSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "scriptfile": - obj.scriptFile = value; + obj.scriptFile = reader.readString(); return true; case "fontdirectory": - obj.fontDirectory = value; + obj.fontDirectory = reader.readString(); return true; case "file": - obj.file = value; + obj.file = reader.readString(); return true; case "tex": - obj.tex = value; - return true; - case "tracks": - obj.tracks = value; + obj.tex = (reader.readBoolean()!); return true; case "visibilitycheckinterval": - obj.visibilityCheckInterval = value; + obj.visibilityCheckInterval = (reader.readNumber()!); return true; case "enablelazyloading": - obj.enableLazyLoading = value; + obj.enableLazyLoading = (reader.readBoolean()!); return true; case "engine": - obj.engine = value; + obj.engine = (reader.readString()!); return true; case "loglevel": - obj.logLevel = isNaN(parseInt(value)) ? LogLevel[Object.keys(LogLevel).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof LogLevel] : parseInt(value); + obj.logLevel = (reader.readEnum(LogLevel)!); return true; case "useworkers": - obj.useWorkers = value; + obj.useWorkers = (reader.readBoolean()!); return true; case "includenotebounds": - obj.includeNoteBounds = value; + obj.includeNoteBounds = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts index 7181dd918..ed818de23 100644 --- a/src/generated/DisplaySettingsSerializer.ts +++ b/src/generated/DisplaySettingsSerializer.ts @@ -4,95 +4,91 @@ // the code is regenerated. // import { DisplaySettings } from "@src/DisplaySettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { RenderingResourcesSerializer } from "@src/generated/RenderingResourcesSerializer"; import { LayoutMode } from "@src/DisplaySettings"; import { StaveProfile } from "@src/DisplaySettings"; -import { RenderingResources } from "@src/RenderingResources"; export class DisplaySettingsSerializer { - public static fromJson(json: any): DisplaySettings { - const obj = new DisplaySettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: DisplaySettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: DisplaySettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; } - } - public static toJson(obj: DisplaySettings | null): any { - if (!obj) { - return null; + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } - const json: any = {}; - this.fillToJson(obj, json); - return json; } - public static fillToJson(obj: DisplaySettings, json: any): void { - json.scale = obj.scale; - json.stretchForce = obj.stretchForce; - json.layoutMode = obj.layoutMode; - json.staveProfile = obj.staveProfile; - json.barsPerRow = obj.barsPerRow; - json.startBar = obj.startBar; - json.barCount = obj.barCount; - json.barCountPerPartial = obj.barCountPerPartial; - if (json.resources) { - RenderingResourcesSerializer.fillToJson(obj.resources, json.resources); - } - else { - json.resources = (RenderingResourcesSerializer.toJson(obj.resources)!); + public static toJson(obj: DisplaySettings | null, writer: IJsonWriter): void { + if (!obj) { + writer.writeNull(); + return; } - json.padding = obj.padding ? obj.padding.slice() : null; + writer.writeStartObject(); + writer.writePropertyName("scale"); + writer.writeNumber(obj.scale); + writer.writePropertyName("stretchForce"); + writer.writeNumber(obj.stretchForce); + writer.writePropertyName("layoutMode"); + writer.writeEnum(obj.layoutMode); + writer.writePropertyName("staveProfile"); + writer.writeEnum(obj.staveProfile); + writer.writePropertyName("barsPerRow"); + writer.writeNumber(obj.barsPerRow); + writer.writePropertyName("startBar"); + writer.writeNumber(obj.startBar); + writer.writePropertyName("barCount"); + writer.writeNumber(obj.barCount); + writer.writePropertyName("barCountPerPartial"); + writer.writeNumber(obj.barCountPerPartial); + writer.writePropertyName("resources"); + RenderingResourcesSerializer.toJson(obj.resources, writer); + writer.writePropertyName("padding"); + writer.writeFloat32Array(obj.padding); + writer.writeEndObject(); } - public static setProperty(obj: DisplaySettings, property: string, value: any): boolean { + public static setProperty(obj: DisplaySettings, property: string, reader: IJsonReader): boolean { switch (property) { case "scale": - obj.scale = value; + obj.scale = (reader.readNumber()!); return true; case "stretchforce": - obj.stretchForce = value; + obj.stretchForce = (reader.readNumber()!); return true; case "layoutmode": - obj.layoutMode = isNaN(parseInt(value)) ? LayoutMode[Object.keys(LayoutMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof LayoutMode] : parseInt(value); + obj.layoutMode = (reader.readEnum(LayoutMode)!); return true; case "staveprofile": - obj.staveProfile = isNaN(parseInt(value)) ? StaveProfile[Object.keys(StaveProfile).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof StaveProfile] : parseInt(value); + obj.staveProfile = (reader.readEnum(StaveProfile)!); return true; case "barsperrow": - obj.barsPerRow = value; + obj.barsPerRow = (reader.readNumber()!); return true; case "startbar": - obj.startBar = value; + obj.startBar = (reader.readNumber()!); return true; case "barcount": - obj.barCount = value; + obj.barCount = (reader.readNumber()!); return true; case "barcountperpartial": - obj.barCountPerPartial = value; + obj.barCountPerPartial = (reader.readNumber()!); return true; case "padding": - obj.padding = value ? value.slice() : null; + obj.padding = reader.readFloat32Array(); return true; } if (["resources"].indexOf(property) >= 0) { - if (obj.resources) - RenderingResourcesSerializer.fillFromJson(obj.resources, value); - else - obj.resources = RenderingResourcesSerializer.fromJson(value); + RenderingResourcesSerializer.fromJson(obj.resources, reader); return true; } else { - for (const $c of ["resources"]) - if (property.indexOf($c) === 0) { - if (!obj.resources) { - obj.resources = new RenderingResources(); - } - if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring($c.length), value)) { + for (const c of ["resources"]) { + if (property.indexOf(c) === 0) { + if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), reader)) { return true; } } + } } return false; } diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts index 5ca67b845..bf1509c1e 100644 --- a/src/generated/ImporterSettingsSerializer.ts +++ b/src/generated/ImporterSettingsSerializer.ts @@ -4,38 +4,37 @@ // the code is regenerated. // import { ImporterSettings } from "@src/ImporterSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class ImporterSettingsSerializer { - public static fromJson(json: any): ImporterSettings { - const obj = new ImporterSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: ImporterSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: ImporterSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: ImporterSettings | null): any { + public static toJson(obj: ImporterSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: ImporterSettings, json: any): void { - json.encoding = obj.encoding; - json.mergePartGroupsInMusicXml = obj.mergePartGroupsInMusicXml; + writer.writeStartObject(); + writer.writePropertyName("encoding"); + writer.writeString(obj.encoding); + writer.writePropertyName("mergePartGroupsInMusicXml"); + writer.writeBoolean(obj.mergePartGroupsInMusicXml); + writer.writeEndObject(); } - public static setProperty(obj: ImporterSettings, property: string, value: any): boolean { + public static setProperty(obj: ImporterSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "encoding": - obj.encoding = value; + obj.encoding = (reader.readString()!); return true; case "mergepartgroupsinmusicxml": - obj.mergePartGroupsInMusicXml = value; + obj.mergePartGroupsInMusicXml = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index bd5ea3a4b..576cfe3b1 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -4,82 +4,91 @@ // the code is regenerated. // import { NotationSettings } from "@src/NotationSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { NotationMode } from "@src/NotationSettings"; import { FingeringMode } from "@src/NotationSettings"; import { NotationElement } from "@src/NotationSettings"; import { TabRhythmMode } from "@src/NotationSettings"; export class NotationSettingsSerializer { - public static fromJson(json: any): NotationSettings { - const obj = new NotationSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: NotationSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: NotationSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: NotationSettings | null): any { + public static toJson(obj: NotationSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: NotationSettings, json: any): void { - json.notationMode = obj.notationMode; - json.fingeringMode = obj.fingeringMode; - json.elements = ({} as any); - obj.elements.forEach(($mv, $mk) => { (json.elements as any)[$mk] = $mv; }); - json.rhythmMode = obj.rhythmMode; - json.rhythmHeight = obj.rhythmHeight; - json.transpositionPitches = obj.transpositionPitches.slice(); - json.displayTranspositionPitches = obj.displayTranspositionPitches.slice(); - json.smallGraceTabNotes = obj.smallGraceTabNotes; - json.extendBendArrowsOnTiedNotes = obj.extendBendArrowsOnTiedNotes; - json.extendLineEffectsToBeatEnd = obj.extendLineEffectsToBeatEnd; - json.slurHeight = obj.slurHeight; + writer.writeStartObject(); + writer.writePropertyName("notationMode"); + writer.writeEnum(obj.notationMode); + writer.writePropertyName("fingeringMode"); + writer.writeEnum(obj.fingeringMode); + writer.writePropertyName("elements"); + writer.writeStartObject(); + obj.elements.forEach((k, v) => { writer.writePropertyName(k); v; }); + writer.writeEndObject(); + writer.writePropertyName("rhythmMode"); + writer.writeEnum(obj.rhythmMode); + writer.writePropertyName("rhythmHeight"); + writer.writeNumber(obj.rhythmHeight); + writer.writePropertyName("transpositionPitches"); + writer.writeNumberArray(obj.transpositionPitches); + writer.writePropertyName("displayTranspositionPitches"); + writer.writeNumberArray(obj.displayTranspositionPitches); + writer.writePropertyName("smallGraceTabNotes"); + writer.writeBoolean(obj.smallGraceTabNotes); + writer.writePropertyName("extendBendArrowsOnTiedNotes"); + writer.writeBoolean(obj.extendBendArrowsOnTiedNotes); + writer.writePropertyName("extendLineEffectsToBeatEnd"); + writer.writeBoolean(obj.extendLineEffectsToBeatEnd); + writer.writePropertyName("slurHeight"); + writer.writeNumber(obj.slurHeight); + writer.writeEndObject(); } - public static setProperty(obj: NotationSettings, property: string, value: any): boolean { + public static setProperty(obj: NotationSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "notationmode": - obj.notationMode = isNaN(parseInt(value)) ? NotationMode[Object.keys(NotationMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof NotationMode] : parseInt(value); + obj.notationMode = (reader.readEnum(NotationMode)!); return true; case "fingeringmode": - obj.fingeringMode = isNaN(parseInt(value)) ? FingeringMode[Object.keys(FingeringMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof FingeringMode] : parseInt(value); + obj.fingeringMode = (reader.readEnum(FingeringMode)!); return true; case "elements": obj.elements = new Map(); - for (let $mk in value) - if (value.hasOwnProperty($mk)) - obj.elements.set(isNaN(parseInt($mk)) ? NotationElement[Object.keys(NotationElement).find($k => $k.toLowerCase() === $mk.toLowerCase()) as keyof typeof NotationElement] : parseInt($mk), value[$mk]); + for (let __mk in value) + if (value.hasOwnProperty(__mk)) + obj.elements.set(reader.readEnum(NotationElement), value[__mk]); return true; case "rhythmmode": - obj.rhythmMode = isNaN(parseInt(value)) ? TabRhythmMode[Object.keys(TabRhythmMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TabRhythmMode] : parseInt(value); + obj.rhythmMode = (reader.readEnum(TabRhythmMode)!); return true; case "rhythmheight": - obj.rhythmHeight = value; + obj.rhythmHeight = (reader.readNumber()!); return true; case "transpositionpitches": - obj.transpositionPitches = value.slice(); + obj.transpositionPitches = (reader.readNumberArray()!); return true; case "displaytranspositionpitches": - obj.displayTranspositionPitches = value.slice(); + obj.displayTranspositionPitches = (reader.readNumberArray()!); return true; case "smallgracetabnotes": - obj.smallGraceTabNotes = value; + obj.smallGraceTabNotes = (reader.readBoolean()!); return true; case "extendbendarrowsontiednotes": - obj.extendBendArrowsOnTiedNotes = value; + obj.extendBendArrowsOnTiedNotes = (reader.readBoolean()!); return true; case "extendlineeffectstobeatend": - obj.extendLineEffectsToBeatEnd = value; + obj.extendLineEffectsToBeatEnd = (reader.readBoolean()!); return true; case "slurheight": - obj.slurHeight = value; + obj.slurHeight = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index 09344ca80..06e8bde78 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -4,79 +4,88 @@ // the code is regenerated. // import { PlayerSettings } from "@src/PlayerSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { - public static fromJson(json: any): PlayerSettings { - const obj = new PlayerSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: PlayerSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: PlayerSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: PlayerSettings | null): any { + public static toJson(obj: PlayerSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: PlayerSettings, json: any): void { - json.soundFont = obj.soundFont; - json.scrollElement = obj.scrollElement; - json.enablePlayer = obj.enablePlayer; - json.enableCursor = obj.enableCursor; - json.enableUserInteraction = obj.enableUserInteraction; - json.scrollOffsetX = obj.scrollOffsetX; - json.scrollOffsetY = obj.scrollOffsetY; - json.scrollMode = obj.scrollMode; - json.scrollSpeed = obj.scrollSpeed; - json.songBookBendDuration = obj.songBookBendDuration; - json.songBookDipDuration = obj.songBookDipDuration; - json.playTripletFeel = obj.playTripletFeel; + writer.writeStartObject(); + writer.writePropertyName("soundFont"); + writer.writeString(obj.soundFont); + writer.writePropertyName("scrollElement"); + writer.writeString(obj.scrollElement); + writer.writePropertyName("enablePlayer"); + writer.writeBoolean(obj.enablePlayer); + writer.writePropertyName("enableCursor"); + writer.writeBoolean(obj.enableCursor); + writer.writePropertyName("enableUserInteraction"); + writer.writeBoolean(obj.enableUserInteraction); + writer.writePropertyName("scrollOffsetX"); + writer.writeNumber(obj.scrollOffsetX); + writer.writePropertyName("scrollOffsetY"); + writer.writeNumber(obj.scrollOffsetY); + writer.writePropertyName("scrollMode"); + writer.writeEnum(obj.scrollMode); + writer.writePropertyName("scrollSpeed"); + writer.writeNumber(obj.scrollSpeed); + writer.writePropertyName("songBookBendDuration"); + writer.writeNumber(obj.songBookBendDuration); + writer.writePropertyName("songBookDipDuration"); + writer.writeNumber(obj.songBookDipDuration); + writer.writePropertyName("playTripletFeel"); + writer.writeBoolean(obj.playTripletFeel); + writer.writeEndObject(); } - public static setProperty(obj: PlayerSettings, property: string, value: any): boolean { + public static setProperty(obj: PlayerSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "soundfont": - obj.soundFont = value; + obj.soundFont = reader.readString(); return true; case "scrollelement": - obj.scrollElement = value; + obj.scrollElement = (reader.readString()!); return true; case "enableplayer": - obj.enablePlayer = value; + obj.enablePlayer = (reader.readBoolean()!); return true; case "enablecursor": - obj.enableCursor = value; + obj.enableCursor = (reader.readBoolean()!); return true; case "enableuserinteraction": - obj.enableUserInteraction = value; + obj.enableUserInteraction = (reader.readBoolean()!); return true; case "scrolloffsetx": - obj.scrollOffsetX = value; + obj.scrollOffsetX = (reader.readNumber()!); return true; case "scrolloffsety": - obj.scrollOffsetY = value; + obj.scrollOffsetY = (reader.readNumber()!); return true; case "scrollmode": - obj.scrollMode = isNaN(parseInt(value)) ? ScrollMode[Object.keys(ScrollMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof ScrollMode] : parseInt(value); + obj.scrollMode = (reader.readEnum(ScrollMode)!); return true; case "scrollspeed": - obj.scrollSpeed = value; + obj.scrollSpeed = (reader.readNumber()!); return true; case "songbookbendduration": - obj.songBookBendDuration = value; + obj.songBookBendDuration = (reader.readNumber()!); return true; case "songbookdipduration": - obj.songBookDipDuration = value; + obj.songBookDipDuration = (reader.readNumber()!); return true; case "playtripletfeel": - obj.playTripletFeel = value; + obj.playTripletFeel = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index 7b158fb30..d3052657e 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -4,49 +4,63 @@ // the code is regenerated. // import { RenderingResources } from "@src/RenderingResources"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { Font } from "@src/model/Font"; import { Color } from "@src/model/Color"; export class RenderingResourcesSerializer { - public static fromJson(json: any): RenderingResources { - const obj = new RenderingResources(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: RenderingResources, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: RenderingResources, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: RenderingResources | null): any { + public static toJson(obj: RenderingResources | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: RenderingResources, json: any): void { - json.copyrightFont = (Font.toJson(obj.copyrightFont)!); - json.titleFont = (Font.toJson(obj.titleFont)!); - json.subTitleFont = (Font.toJson(obj.subTitleFont)!); - json.wordsFont = (Font.toJson(obj.wordsFont)!); - json.effectFont = (Font.toJson(obj.effectFont)!); - json.fretboardNumberFont = (Font.toJson(obj.fretboardNumberFont)!); - json.tablatureFont = (Font.toJson(obj.tablatureFont)!); - json.graceFont = (Font.toJson(obj.graceFont)!); - json.staffLineColor = (Color.toJson(obj.staffLineColor)!); - json.barSeparatorColor = (Color.toJson(obj.barSeparatorColor)!); - json.barNumberFont = (Font.toJson(obj.barNumberFont)!); - json.barNumberColor = (Color.toJson(obj.barNumberColor)!); - json.fingeringFont = (Font.toJson(obj.fingeringFont)!); - json.markerFont = (Font.toJson(obj.markerFont)!); - json.mainGlyphColor = (Color.toJson(obj.mainGlyphColor)!); - json.secondaryGlyphColor = (Color.toJson(obj.secondaryGlyphColor)!); - json.scoreInfoColor = (Color.toJson(obj.scoreInfoColor)!); + writer.writeStartObject(); + writer.writePropertyName("copyrightFont"); + Font.toJson(obj.copyrightFont, writer); + writer.writePropertyName("titleFont"); + Font.toJson(obj.titleFont, writer); + writer.writePropertyName("subTitleFont"); + Font.toJson(obj.subTitleFont, writer); + writer.writePropertyName("wordsFont"); + Font.toJson(obj.wordsFont, writer); + writer.writePropertyName("effectFont"); + Font.toJson(obj.effectFont, writer); + writer.writePropertyName("fretboardNumberFont"); + Font.toJson(obj.fretboardNumberFont, writer); + writer.writePropertyName("tablatureFont"); + Font.toJson(obj.tablatureFont, writer); + writer.writePropertyName("graceFont"); + Font.toJson(obj.graceFont, writer); + writer.writePropertyName("staffLineColor"); + Color.toJson(obj.staffLineColor, writer); + writer.writePropertyName("barSeparatorColor"); + Color.toJson(obj.barSeparatorColor, writer); + writer.writePropertyName("barNumberFont"); + Font.toJson(obj.barNumberFont, writer); + writer.writePropertyName("barNumberColor"); + Color.toJson(obj.barNumberColor, writer); + writer.writePropertyName("fingeringFont"); + Font.toJson(obj.fingeringFont, writer); + writer.writePropertyName("markerFont"); + Font.toJson(obj.markerFont, writer); + writer.writePropertyName("mainGlyphColor"); + Color.toJson(obj.mainGlyphColor, writer); + writer.writePropertyName("secondaryGlyphColor"); + Color.toJson(obj.secondaryGlyphColor, writer); + writer.writePropertyName("scoreInfoColor"); + Color.toJson(obj.scoreInfoColor, writer); + writer.writeEndObject(); } - public static setProperty(obj: RenderingResources, property: string, value: any): boolean { + public static setProperty(obj: RenderingResources, property: string, reader: IJsonReader): boolean { switch (property) { case "copyrightfont": obj.copyrightFont = (Font.fromJson(value)!); diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts index 2a821759a..4c11fb7ec 100644 --- a/src/generated/SettingsSerializer.ts +++ b/src/generated/SettingsSerializer.ts @@ -4,31 +4,109 @@ // the code is regenerated. // import { Settings } from "@src/Settings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; +import { CoreSettingsSerializer } from "@src/generated/CoreSettingsSerializer"; +import { DisplaySettingsSerializer } from "@src/generated/DisplaySettingsSerializer"; +import { NotationSettingsSerializer } from "@src/generated/NotationSettingsSerializer"; +import { ImporterSettingsSerializer } from "@src/generated/ImporterSettingsSerializer"; +import { PlayerSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; export class SettingsSerializer { - public static fromJson(json: any): Settings { - const obj = new Settings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Settings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Settings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Settings | null): any { + public static toJson(obj: Settings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; + writer.writeStartObject(); + writer.writePropertyName("core"); + CoreSettingsSerializer.toJson(obj.core, writer); + writer.writePropertyName("display"); + DisplaySettingsSerializer.toJson(obj.display, writer); + writer.writePropertyName("notation"); + NotationSettingsSerializer.toJson(obj.notation, writer); + writer.writePropertyName("importer"); + ImporterSettingsSerializer.toJson(obj.importer, writer); + writer.writePropertyName("player"); + PlayerSettingsSerializer.toJson(obj.player, writer); + writer.writeEndObject(); } - public static fillToJson(obj: Settings, json: any): void { } - public static setProperty(obj: Settings, property: string, value: any): boolean { + public static setProperty(obj: Settings, property: string, reader: IJsonReader): boolean { switch (property) { } + if (["core", ""].indexOf(property) >= 0) { + CoreSettingsSerializer.fromJson(obj.core, reader); + return true; + } + else { + for (const c of ["core", ""]) { + if (property.indexOf(c) === 0) { + if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), reader)) { + return true; + } + } + } + } + if (["display", ""].indexOf(property) >= 0) { + DisplaySettingsSerializer.fromJson(obj.display, reader); + return true; + } + else { + for (const c of ["display", ""]) { + if (property.indexOf(c) === 0) { + if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), reader)) { + return true; + } + } + } + } + if (["notation"].indexOf(property) >= 0) { + NotationSettingsSerializer.fromJson(obj.notation, reader); + return true; + } + else { + for (const c of ["notation"]) { + if (property.indexOf(c) === 0) { + if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), reader)) { + return true; + } + } + } + } + if (["importer"].indexOf(property) >= 0) { + ImporterSettingsSerializer.fromJson(obj.importer, reader); + return true; + } + else { + for (const c of ["importer"]) { + if (property.indexOf(c) === 0) { + if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), reader)) { + return true; + } + } + } + } + if (["player"].indexOf(property) >= 0) { + PlayerSettingsSerializer.fromJson(obj.player, reader); + return true; + } + else { + for (const c of ["player"]) { + if (property.indexOf(c) === 0) { + if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), reader)) { + return true; + } + } + } + } return false; } } diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts index 9286d5796..d93a1a363 100644 --- a/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -4,42 +4,42 @@ // the code is regenerated. // import { SlidePlaybackSettings } from "@src/PlayerSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class SlidePlaybackSettingsSerializer { - public static fromJson(json: any): SlidePlaybackSettings { - const obj = new SlidePlaybackSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: SlidePlaybackSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: SlidePlaybackSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: SlidePlaybackSettings | null): any { + public static toJson(obj: SlidePlaybackSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: SlidePlaybackSettings, json: any): void { - json.simpleSlidePitchOffset = obj.simpleSlidePitchOffset; - json.simpleSlideDurationRatio = obj.simpleSlideDurationRatio; - json.shiftSlideDurationRatio = obj.shiftSlideDurationRatio; + writer.writeStartObject(); + writer.writePropertyName("simpleSlidePitchOffset"); + writer.writeNumber(obj.simpleSlidePitchOffset); + writer.writePropertyName("simpleSlideDurationRatio"); + writer.writeNumber(obj.simpleSlideDurationRatio); + writer.writePropertyName("shiftSlideDurationRatio"); + writer.writeNumber(obj.shiftSlideDurationRatio); + writer.writeEndObject(); } - public static setProperty(obj: SlidePlaybackSettings, property: string, value: any): boolean { + public static setProperty(obj: SlidePlaybackSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "simpleslidepitchoffset": - obj.simpleSlidePitchOffset = value; + obj.simpleSlidePitchOffset = (reader.readNumber()!); return true; case "simpleslidedurationratio": - obj.simpleSlideDurationRatio = value; + obj.simpleSlideDurationRatio = (reader.readNumber()!); return true; case "shiftslidedurationratio": - obj.shiftSlideDurationRatio = value; + obj.shiftSlideDurationRatio = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts index 877bad139..f953caf48 100644 --- a/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -4,62 +4,67 @@ // the code is regenerated. // import { VibratoPlaybackSettings } from "@src/PlayerSettings"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class VibratoPlaybackSettingsSerializer { - public static fromJson(json: any): VibratoPlaybackSettings { - const obj = new VibratoPlaybackSettings(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: VibratoPlaybackSettings, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: VibratoPlaybackSettings, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: VibratoPlaybackSettings | null): any { + public static toJson(obj: VibratoPlaybackSettings | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: VibratoPlaybackSettings, json: any): void { - json.noteWideLength = obj.noteWideLength; - json.noteWideAmplitude = obj.noteWideAmplitude; - json.noteSlightLength = obj.noteSlightLength; - json.noteSlightAmplitude = obj.noteSlightAmplitude; - json.beatWideLength = obj.beatWideLength; - json.beatWideAmplitude = obj.beatWideAmplitude; - json.beatSlightLength = obj.beatSlightLength; - json.beatSlightAmplitude = obj.beatSlightAmplitude; + writer.writeStartObject(); + writer.writePropertyName("noteWideLength"); + writer.writeNumber(obj.noteWideLength); + writer.writePropertyName("noteWideAmplitude"); + writer.writeNumber(obj.noteWideAmplitude); + writer.writePropertyName("noteSlightLength"); + writer.writeNumber(obj.noteSlightLength); + writer.writePropertyName("noteSlightAmplitude"); + writer.writeNumber(obj.noteSlightAmplitude); + writer.writePropertyName("beatWideLength"); + writer.writeNumber(obj.beatWideLength); + writer.writePropertyName("beatWideAmplitude"); + writer.writeNumber(obj.beatWideAmplitude); + writer.writePropertyName("beatSlightLength"); + writer.writeNumber(obj.beatSlightLength); + writer.writePropertyName("beatSlightAmplitude"); + writer.writeNumber(obj.beatSlightAmplitude); + writer.writeEndObject(); } - public static setProperty(obj: VibratoPlaybackSettings, property: string, value: any): boolean { + public static setProperty(obj: VibratoPlaybackSettings, property: string, reader: IJsonReader): boolean { switch (property) { case "notewidelength": - obj.noteWideLength = value; + obj.noteWideLength = (reader.readNumber()!); return true; case "notewideamplitude": - obj.noteWideAmplitude = value; + obj.noteWideAmplitude = (reader.readNumber()!); return true; case "noteslightlength": - obj.noteSlightLength = value; + obj.noteSlightLength = (reader.readNumber()!); return true; case "noteslightamplitude": - obj.noteSlightAmplitude = value; + obj.noteSlightAmplitude = (reader.readNumber()!); return true; case "beatwidelength": - obj.beatWideLength = value; + obj.beatWideLength = (reader.readNumber()!); return true; case "beatwideamplitude": - obj.beatWideAmplitude = value; + obj.beatWideAmplitude = (reader.readNumber()!); return true; case "beatslightlength": - obj.beatSlightLength = value; + obj.beatSlightLength = (reader.readNumber()!); return true; case "beatslightamplitude": - obj.beatSlightAmplitude = value; + obj.beatSlightAmplitude = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts index 0a0cc2357..e5d48b0f7 100644 --- a/src/generated/model/AutomationSerializer.ts +++ b/src/generated/model/AutomationSerializer.ts @@ -4,51 +4,53 @@ // the code is regenerated. // import { Automation } from "@src/model/Automation"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { AutomationType } from "@src/model/Automation"; export class AutomationSerializer { - public static fromJson(json: any): Automation { - const obj = new Automation(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Automation, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Automation, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Automation | null): any { + public static toJson(obj: Automation | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Automation, json: any): void { - json.isLinear = obj.isLinear; - json.type = obj.type; - json.value = obj.value; - json.ratioPosition = obj.ratioPosition; - json.text = obj.text; + writer.writeStartObject(); + writer.writePropertyName("isLinear"); + writer.writeBoolean(obj.isLinear); + writer.writePropertyName("type"); + writer.writeEnum(obj.type); + writer.writePropertyName("value"); + writer.writeNumber(obj.value); + writer.writePropertyName("ratioPosition"); + writer.writeNumber(obj.ratioPosition); + writer.writePropertyName("text"); + writer.writeString(obj.text); + writer.writeEndObject(); } - public static setProperty(obj: Automation, property: string, value: any): boolean { + public static setProperty(obj: Automation, property: string, reader: IJsonReader): boolean { switch (property) { case "islinear": - obj.isLinear = value; + obj.isLinear = (reader.readBoolean()!); return true; case "type": - obj.type = isNaN(parseInt(value)) ? AutomationType[Object.keys(AutomationType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof AutomationType] : parseInt(value); + obj.type = (reader.readEnum(AutomationType)!); return true; case "value": - obj.value = value; + obj.value = (reader.readNumber()!); return true; case "ratioposition": - obj.ratioPosition = value; + obj.ratioPosition = (reader.readNumber()!); return true; case "text": - obj.text = value; + obj.text = (reader.readString()!); return true; } return false; diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index 05164fcbd..aaca6ca16 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -4,60 +4,67 @@ // the code is regenerated. // import { Bar } from "@src/model/Bar"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { VoiceSerializer } from "@src/generated/model/VoiceSerializer"; import { Clef } from "@src/model/Clef"; import { Ottavia } from "@src/model/Ottavia"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { - public static fromJson(json: any): Bar { - const obj = new Bar(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Bar, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Bar, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Bar | null): any { + public static toJson(obj: Bar | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Bar, json: any): void { - json.id = obj.id; - json.index = obj.index; - json.clef = obj.clef; - json.clefOttava = obj.clefOttava; - json.voices = obj.voices.map($li => VoiceSerializer.toJson($li)); - json.simileMark = obj.simileMark; + writer.writeStartObject(); + writer.writePropertyName("id"); + writer.writeNumber(obj.id); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("clef"); + writer.writeEnum(obj.clef); + writer.writePropertyName("clefOttava"); + writer.writeEnum(obj.clefOttava); + writer.writePropertyName("voices"); + writer.writeStartArray(); + for (const i of obj.voices) { + VoiceSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("simileMark"); + writer.writeEnum(obj.simileMark); + writer.writeEndObject(); } - public static setProperty(obj: Bar, property: string, value: any): boolean { + public static setProperty(obj: Bar, property: string, reader: IJsonReader): boolean { switch (property) { case "id": - obj.id = value; + obj.id = (reader.readNumber()!); return true; case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "clef": - obj.clef = isNaN(parseInt(value)) ? Clef[Object.keys(Clef).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Clef] : parseInt(value); + obj.clef = (reader.readEnum(Clef)!); return true; case "clefottava": - obj.clefOttava = isNaN(parseInt(value)) ? Ottavia[Object.keys(Ottavia).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Ottavia] : parseInt(value); + obj.clefOttava = (reader.readEnum(Ottavia)!); return true; case "voices": obj.voices = []; - for (const $li of value) - obj.addVoice(VoiceSerializer.fromJson($li)); + for (const __li of value) + obj.addVoice(VoiceSerializer.fromJson(i, j)); return true; case "similemark": - obj.simileMark = isNaN(parseInt(value)) ? SimileMark[Object.keys(SimileMark).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SimileMark] : parseInt(value); + obj.simileMark = (reader.readEnum(SimileMark)!); return true; } return false; diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index 0b0bedcfa..a8653b542 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -4,6 +4,9 @@ // the code is regenerated. // import { Beat } from "@src/model/Beat"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { NoteSerializer } from "@src/generated/model/NoteSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; @@ -20,199 +23,246 @@ import { DynamicValue } from "@src/model/DynamicValue"; import { BeamDirection } from "@src/rendering/utils/BeamDirection"; import { BeatBeamingMode } from "@src/model/Beat"; export class BeatSerializer { - public static fromJson(json: any): Beat { - const obj = new Beat(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Beat, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Beat, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Beat | null): any { + public static toJson(obj: Beat | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Beat, json: any): void { - json.id = obj.id; - json.index = obj.index; - json.notes = obj.notes.map($li => NoteSerializer.toJson($li)); - json.isEmpty = obj.isEmpty; - json.whammyStyle = obj.whammyStyle; - json.ottava = obj.ottava; - json.isLegatoOrigin = obj.isLegatoOrigin; - json.duration = obj.duration; - json.isLetRing = obj.isLetRing; - json.isPalmMute = obj.isPalmMute; - json.automations = obj.automations.map($li => AutomationSerializer.toJson($li)); - json.dots = obj.dots; - json.fadeIn = obj.fadeIn; - json.lyrics = obj.lyrics ? obj.lyrics.slice() : null; - json.hasRasgueado = obj.hasRasgueado; - json.pop = obj.pop; - json.slap = obj.slap; - json.tap = obj.tap; - json.text = obj.text; - json.brushType = obj.brushType; - json.brushDuration = obj.brushDuration; - json.tupletDenominator = obj.tupletDenominator; - json.tupletNumerator = obj.tupletNumerator; - json.isContinuedWhammy = obj.isContinuedWhammy; - json.whammyBarType = obj.whammyBarType; - json.whammyBarPoints = obj.whammyBarPoints.map($li => BendPointSerializer.toJson($li)); - json.vibrato = obj.vibrato; - json.chordId = obj.chordId; - json.graceType = obj.graceType; - json.pickStroke = obj.pickStroke; - json.tremoloSpeed = obj.tremoloSpeed; - json.crescendo = obj.crescendo; - json.displayStart = obj.displayStart; - json.playbackStart = obj.playbackStart; - json.displayDuration = obj.displayDuration; - json.playbackDuration = obj.playbackDuration; - json.dynamics = obj.dynamics; - json.invertBeamDirection = obj.invertBeamDirection; - json.preferredBeamDirection = obj.preferredBeamDirection; - json.isEffectSlurOrigin = obj.isEffectSlurOrigin; - json.beamingMode = obj.beamingMode; + writer.writeStartObject(); + writer.writePropertyName("id"); + writer.writeNumber(obj.id); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("notes"); + writer.writeStartArray(); + for (const i of obj.notes) { + NoteSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("isEmpty"); + writer.writeBoolean(obj.isEmpty); + writer.writePropertyName("whammyStyle"); + writer.writeEnum(obj.whammyStyle); + writer.writePropertyName("ottava"); + writer.writeEnum(obj.ottava); + writer.writePropertyName("isLegatoOrigin"); + writer.writeBoolean(obj.isLegatoOrigin); + writer.writePropertyName("duration"); + writer.writeEnum(obj.duration); + writer.writePropertyName("isLetRing"); + writer.writeBoolean(obj.isLetRing); + writer.writePropertyName("isPalmMute"); + writer.writeBoolean(obj.isPalmMute); + writer.writePropertyName("automations"); + writer.writeStartArray(); + for (const i of obj.automations) { + AutomationSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("dots"); + writer.writeNumber(obj.dots); + writer.writePropertyName("fadeIn"); + writer.writeBoolean(obj.fadeIn); + writer.writePropertyName("lyrics"); + writer.writeStringArray(obj.lyrics); + writer.writePropertyName("hasRasgueado"); + writer.writeBoolean(obj.hasRasgueado); + writer.writePropertyName("pop"); + writer.writeBoolean(obj.pop); + writer.writePropertyName("slap"); + writer.writeBoolean(obj.slap); + writer.writePropertyName("tap"); + writer.writeBoolean(obj.tap); + writer.writePropertyName("text"); + writer.writeString(obj.text); + writer.writePropertyName("brushType"); + writer.writeEnum(obj.brushType); + writer.writePropertyName("brushDuration"); + writer.writeNumber(obj.brushDuration); + writer.writePropertyName("tupletDenominator"); + writer.writeNumber(obj.tupletDenominator); + writer.writePropertyName("tupletNumerator"); + writer.writeNumber(obj.tupletNumerator); + writer.writePropertyName("isContinuedWhammy"); + writer.writeBoolean(obj.isContinuedWhammy); + writer.writePropertyName("whammyBarType"); + writer.writeEnum(obj.whammyBarType); + writer.writePropertyName("whammyBarPoints"); + writer.writeStartArray(); + for (const i of obj.whammyBarPoints) { + BendPointSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("vibrato"); + writer.writeEnum(obj.vibrato); + writer.writePropertyName("chordId"); + writer.writeString(obj.chordId); + writer.writePropertyName("graceType"); + writer.writeEnum(obj.graceType); + writer.writePropertyName("pickStroke"); + writer.writeEnum(obj.pickStroke); + writer.writePropertyName("tremoloSpeed"); + writer.writeEnum(obj.tremoloSpeed); + writer.writePropertyName("crescendo"); + writer.writeEnum(obj.crescendo); + writer.writePropertyName("displayStart"); + writer.writeNumber(obj.displayStart); + writer.writePropertyName("playbackStart"); + writer.writeNumber(obj.playbackStart); + writer.writePropertyName("displayDuration"); + writer.writeNumber(obj.displayDuration); + writer.writePropertyName("playbackDuration"); + writer.writeNumber(obj.playbackDuration); + writer.writePropertyName("dynamics"); + writer.writeEnum(obj.dynamics); + writer.writePropertyName("invertBeamDirection"); + writer.writeBoolean(obj.invertBeamDirection); + writer.writePropertyName("preferredBeamDirection"); + writer.writeEnum(obj.preferredBeamDirection); + writer.writePropertyName("isEffectSlurOrigin"); + writer.writeBoolean(obj.isEffectSlurOrigin); + writer.writePropertyName("beamingMode"); + writer.writeEnum(obj.beamingMode); + writer.writeEndObject(); } - public static setProperty(obj: Beat, property: string, value: any): boolean { + public static setProperty(obj: Beat, property: string, reader: IJsonReader): boolean { switch (property) { case "id": - obj.id = value; + obj.id = (reader.readNumber()!); return true; case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "notes": obj.notes = []; - for (const $li of value) - obj.addNote(NoteSerializer.fromJson($li)); + for (const __li of value) + obj.addNote(NoteSerializer.fromJson(i, j)); return true; case "isempty": - obj.isEmpty = value; + obj.isEmpty = (reader.readBoolean()!); return true; case "whammystyle": - obj.whammyStyle = isNaN(parseInt(value)) ? BendStyle[Object.keys(BendStyle).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendStyle] : parseInt(value); + obj.whammyStyle = (reader.readEnum(BendStyle)!); return true; case "ottava": - obj.ottava = isNaN(parseInt(value)) ? Ottavia[Object.keys(Ottavia).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Ottavia] : parseInt(value); + obj.ottava = (reader.readEnum(Ottavia)!); return true; case "islegatoorigin": - obj.isLegatoOrigin = value; + obj.isLegatoOrigin = (reader.readBoolean()!); return true; case "duration": - obj.duration = isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + obj.duration = (reader.readEnum(Duration)!); return true; case "isletring": - obj.isLetRing = value; + obj.isLetRing = (reader.readBoolean()!); return true; case "ispalmmute": - obj.isPalmMute = value; + obj.isPalmMute = (reader.readBoolean()!); return true; case "automations": obj.automations = []; - for (const $li of value) - obj.automations.push(AutomationSerializer.fromJson($li)); + for (const __li of value) + obj.automations.push(AutomationSerializer.fromJson(i, j)); return true; case "dots": - obj.dots = value; + obj.dots = (reader.readNumber()!); return true; case "fadein": - obj.fadeIn = value; + obj.fadeIn = (reader.readBoolean()!); return true; case "lyrics": - obj.lyrics = value ? value.slice() : null; + obj.lyrics = reader.readStringArray(); return true; case "hasrasgueado": - obj.hasRasgueado = value; + obj.hasRasgueado = (reader.readBoolean()!); return true; case "pop": - obj.pop = value; + obj.pop = (reader.readBoolean()!); return true; case "slap": - obj.slap = value; + obj.slap = (reader.readBoolean()!); return true; case "tap": - obj.tap = value; + obj.tap = (reader.readBoolean()!); return true; case "text": - obj.text = value; + obj.text = reader.readString(); return true; case "brushtype": - obj.brushType = isNaN(parseInt(value)) ? BrushType[Object.keys(BrushType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BrushType] : parseInt(value); + obj.brushType = (reader.readEnum(BrushType)!); return true; case "brushduration": - obj.brushDuration = value; + obj.brushDuration = (reader.readNumber()!); return true; case "tupletdenominator": - obj.tupletDenominator = value; + obj.tupletDenominator = (reader.readNumber()!); return true; case "tupletnumerator": - obj.tupletNumerator = value; + obj.tupletNumerator = (reader.readNumber()!); return true; case "iscontinuedwhammy": - obj.isContinuedWhammy = value; + obj.isContinuedWhammy = (reader.readBoolean()!); return true; case "whammybartype": - obj.whammyBarType = isNaN(parseInt(value)) ? WhammyType[Object.keys(WhammyType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof WhammyType] : parseInt(value); + obj.whammyBarType = (reader.readEnum(WhammyType)!); return true; case "whammybarpoints": obj.whammyBarPoints = []; - for (const $li of value) - obj.addWhammyBarPoint(BendPointSerializer.fromJson($li)); + for (const __li of value) + obj.addWhammyBarPoint(BendPointSerializer.fromJson(i, j)); return true; case "vibrato": - obj.vibrato = isNaN(parseInt(value)) ? VibratoType[Object.keys(VibratoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof VibratoType] : parseInt(value); + obj.vibrato = (reader.readEnum(VibratoType)!); return true; case "chordid": - obj.chordId = value; + obj.chordId = reader.readString(); return true; case "gracetype": - obj.graceType = isNaN(parseInt(value)) ? GraceType[Object.keys(GraceType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof GraceType] : parseInt(value); + obj.graceType = (reader.readEnum(GraceType)!); return true; case "pickstroke": - obj.pickStroke = isNaN(parseInt(value)) ? PickStroke[Object.keys(PickStroke).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof PickStroke] : parseInt(value); + obj.pickStroke = (reader.readEnum(PickStroke)!); return true; case "tremolospeed": - obj.tremoloSpeed = value === null ? null : isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + obj.tremoloSpeed = reader.readEnum(Duration); return true; case "crescendo": - obj.crescendo = isNaN(parseInt(value)) ? CrescendoType[Object.keys(CrescendoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof CrescendoType] : parseInt(value); + obj.crescendo = (reader.readEnum(CrescendoType)!); return true; case "displaystart": - obj.displayStart = value; + obj.displayStart = (reader.readNumber()!); return true; case "playbackstart": - obj.playbackStart = value; + obj.playbackStart = (reader.readNumber()!); return true; case "displayduration": - obj.displayDuration = value; + obj.displayDuration = (reader.readNumber()!); return true; case "playbackduration": - obj.playbackDuration = value; + obj.playbackDuration = (reader.readNumber()!); return true; case "dynamics": - obj.dynamics = isNaN(parseInt(value)) ? DynamicValue[Object.keys(DynamicValue).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof DynamicValue] : parseInt(value); + obj.dynamics = (reader.readEnum(DynamicValue)!); return true; case "invertbeamdirection": - obj.invertBeamDirection = value; + obj.invertBeamDirection = (reader.readBoolean()!); return true; case "preferredbeamdirection": - obj.preferredBeamDirection = value === null ? null : isNaN(parseInt(value)) ? BeamDirection[Object.keys(BeamDirection).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BeamDirection] : parseInt(value); + obj.preferredBeamDirection = reader.readEnum(BeamDirection); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = value; + obj.isEffectSlurOrigin = (reader.readBoolean()!); return true; case "beamingmode": - obj.beamingMode = isNaN(parseInt(value)) ? BeatBeamingMode[Object.keys(BeatBeamingMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BeatBeamingMode] : parseInt(value); + obj.beamingMode = (reader.readEnum(BeatBeamingMode)!); return true; } return false; diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts index da5821063..f16187d42 100644 --- a/src/generated/model/BendPointSerializer.ts +++ b/src/generated/model/BendPointSerializer.ts @@ -4,38 +4,37 @@ // the code is regenerated. // import { BendPoint } from "@src/model/BendPoint"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class BendPointSerializer { - public static fromJson(json: any): BendPoint { - const obj = new BendPoint(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: BendPoint, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: BendPoint, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: BendPoint | null): any { + public static toJson(obj: BendPoint | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: BendPoint, json: any): void { - json.offset = obj.offset; - json.value = obj.value; + writer.writeStartObject(); + writer.writePropertyName("offset"); + writer.writeNumber(obj.offset); + writer.writePropertyName("value"); + writer.writeNumber(obj.value); + writer.writeEndObject(); } - public static setProperty(obj: BendPoint, property: string, value: any): boolean { + public static setProperty(obj: BendPoint, property: string, reader: IJsonReader): boolean { switch (property) { case "offset": - obj.offset = value; + obj.offset = (reader.readNumber()!); return true; case "value": - obj.value = value; + obj.value = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts index 043d441aa..7414d7a91 100644 --- a/src/generated/model/ChordSerializer.ts +++ b/src/generated/model/ChordSerializer.ts @@ -4,58 +4,62 @@ // the code is regenerated. // import { Chord } from "@src/model/Chord"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class ChordSerializer { - public static fromJson(json: any): Chord { - const obj = new Chord(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Chord, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Chord, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Chord | null): any { + public static toJson(obj: Chord | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Chord, json: any): void { - json.name = obj.name; - json.firstFret = obj.firstFret; - json.strings = obj.strings.slice(); - json.barreFrets = obj.barreFrets.slice(); - json.showName = obj.showName; - json.showDiagram = obj.showDiagram; - json.showFingering = obj.showFingering; + writer.writeStartObject(); + writer.writePropertyName("name"); + writer.writeString(obj.name); + writer.writePropertyName("firstFret"); + writer.writeNumber(obj.firstFret); + writer.writePropertyName("strings"); + writer.writeNumberArray(obj.strings); + writer.writePropertyName("barreFrets"); + writer.writeNumberArray(obj.barreFrets); + writer.writePropertyName("showName"); + writer.writeBoolean(obj.showName); + writer.writePropertyName("showDiagram"); + writer.writeBoolean(obj.showDiagram); + writer.writePropertyName("showFingering"); + writer.writeBoolean(obj.showFingering); + writer.writeEndObject(); } - public static setProperty(obj: Chord, property: string, value: any): boolean { + public static setProperty(obj: Chord, property: string, reader: IJsonReader): boolean { switch (property) { case "name": - obj.name = value; + obj.name = (reader.readString()!); return true; case "firstfret": - obj.firstFret = value; + obj.firstFret = (reader.readNumber()!); return true; case "strings": - obj.strings = value.slice(); + obj.strings = (reader.readNumberArray()!); return true; case "barrefrets": - obj.barreFrets = value.slice(); + obj.barreFrets = (reader.readNumberArray()!); return true; case "showname": - obj.showName = value; + obj.showName = (reader.readBoolean()!); return true; case "showdiagram": - obj.showDiagram = value; + obj.showDiagram = (reader.readBoolean()!); return true; case "showfingering": - obj.showFingering = value; + obj.showFingering = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts index 6ba1d326e..8dded0b76 100644 --- a/src/generated/model/FermataSerializer.ts +++ b/src/generated/model/FermataSerializer.ts @@ -4,39 +4,38 @@ // the code is regenerated. // import { Fermata } from "@src/model/Fermata"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { FermataType } from "@src/model/Fermata"; export class FermataSerializer { - public static fromJson(json: any): Fermata { - const obj = new Fermata(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Fermata, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Fermata, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Fermata | null): any { + public static toJson(obj: Fermata | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Fermata, json: any): void { - json.type = obj.type; - json.length = obj.length; + writer.writeStartObject(); + writer.writePropertyName("type"); + writer.writeEnum(obj.type); + writer.writePropertyName("length"); + writer.writeNumber(obj.length); + writer.writeEndObject(); } - public static setProperty(obj: Fermata, property: string, value: any): boolean { + public static setProperty(obj: Fermata, property: string, reader: IJsonReader): boolean { switch (property) { case "type": - obj.type = isNaN(parseInt(value)) ? FermataType[Object.keys(FermataType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof FermataType] : parseInt(value); + obj.type = (reader.readEnum(FermataType)!); return true; case "length": - obj.length = value; + obj.length = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts index 03a6274c6..737f46970 100644 --- a/src/generated/model/InstrumentArticulationSerializer.ts +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -4,60 +4,64 @@ // the code is regenerated. // import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; import { TextBaseline } from "@src/platform/ICanvas"; export class InstrumentArticulationSerializer { - public static fromJson(json: any): InstrumentArticulation { - const obj = new InstrumentArticulation(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: InstrumentArticulation, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: InstrumentArticulation, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: InstrumentArticulation | null): any { + public static toJson(obj: InstrumentArticulation | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: InstrumentArticulation, json: any): void { - json.staffLine = obj.staffLine; - json.noteHeadDefault = obj.noteHeadDefault; - json.noteHeadHalf = obj.noteHeadHalf; - json.noteHeadWhole = obj.noteHeadWhole; - json.techniqueSymbol = obj.techniqueSymbol; - json.techniqueSymbolPlacement = obj.techniqueSymbolPlacement; - json.outputMidiNumber = obj.outputMidiNumber; + writer.writeStartObject(); + writer.writePropertyName("staffLine"); + writer.writeNumber(obj.staffLine); + writer.writePropertyName("noteHeadDefault"); + writer.writeEnum(obj.noteHeadDefault); + writer.writePropertyName("noteHeadHalf"); + writer.writeEnum(obj.noteHeadHalf); + writer.writePropertyName("noteHeadWhole"); + writer.writeEnum(obj.noteHeadWhole); + writer.writePropertyName("techniqueSymbol"); + writer.writeEnum(obj.techniqueSymbol); + writer.writePropertyName("techniqueSymbolPlacement"); + writer.writeEnum(obj.techniqueSymbolPlacement); + writer.writePropertyName("outputMidiNumber"); + writer.writeNumber(obj.outputMidiNumber); + writer.writeEndObject(); } - public static setProperty(obj: InstrumentArticulation, property: string, value: any): boolean { + public static setProperty(obj: InstrumentArticulation, property: string, reader: IJsonReader): boolean { switch (property) { case "staffline": - obj.staffLine = value; + obj.staffLine = (reader.readNumber()!); return true; case "noteheaddefault": - obj.noteHeadDefault = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + obj.noteHeadDefault = (reader.readEnum(MusicFontSymbol)!); return true; case "noteheadhalf": - obj.noteHeadHalf = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + obj.noteHeadHalf = (reader.readEnum(MusicFontSymbol)!); return true; case "noteheadwhole": - obj.noteHeadWhole = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + obj.noteHeadWhole = (reader.readEnum(MusicFontSymbol)!); return true; case "techniquesymbol": - obj.techniqueSymbol = isNaN(parseInt(value)) ? MusicFontSymbol[Object.keys(MusicFontSymbol).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof MusicFontSymbol] : parseInt(value); + obj.techniqueSymbol = (reader.readEnum(MusicFontSymbol)!); return true; case "techniquesymbolplacement": - obj.techniqueSymbolPlacement = isNaN(parseInt(value)) ? TextBaseline[Object.keys(TextBaseline).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TextBaseline] : parseInt(value); + obj.techniqueSymbolPlacement = (reader.readEnum(TextBaseline)!); return true; case "outputmidinumber": - obj.outputMidiNumber = value; + obj.outputMidiNumber = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index 8a3adf225..dbcd616dc 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -4,6 +4,9 @@ // the code is regenerated. // import { MasterBar } from "@src/model/MasterBar"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { SectionSerializer } from "@src/generated/model/SectionSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { FermataSerializer } from "@src/generated/model/FermataSerializer"; @@ -14,142 +17,131 @@ import { Section } from "@src/model/Section"; import { Automation } from "@src/model/Automation"; import { Fermata } from "@src/model/Fermata"; export class MasterBarSerializer { - public static fromJson(json: any): MasterBar { - const obj = new MasterBar(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: MasterBar, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: MasterBar, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: MasterBar | null): any { + public static toJson(obj: MasterBar | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: MasterBar, json: any): void { - json.alternateEndings = obj.alternateEndings; - json.index = obj.index; - json.keySignature = obj.keySignature; - json.keySignatureType = obj.keySignatureType; - json.isDoubleBar = obj.isDoubleBar; - json.isRepeatStart = obj.isRepeatStart; - json.repeatCount = obj.repeatCount; - json.timeSignatureNumerator = obj.timeSignatureNumerator; - json.timeSignatureDenominator = obj.timeSignatureDenominator; - json.timeSignatureCommon = obj.timeSignatureCommon; - json.tripletFeel = obj.tripletFeel; - if (json.section) { - if (obj.section) { - SectionSerializer.fillToJson(obj.section, json.section); - } + writer.writeStartObject(); + writer.writePropertyName("alternateEndings"); + writer.writeNumber(obj.alternateEndings); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("keySignature"); + writer.writeEnum(obj.keySignature); + writer.writePropertyName("keySignatureType"); + writer.writeEnum(obj.keySignatureType); + writer.writePropertyName("isDoubleBar"); + writer.writeBoolean(obj.isDoubleBar); + writer.writePropertyName("isRepeatStart"); + writer.writeBoolean(obj.isRepeatStart); + writer.writePropertyName("repeatCount"); + writer.writeNumber(obj.repeatCount); + writer.writePropertyName("timeSignatureNumerator"); + writer.writeNumber(obj.timeSignatureNumerator); + writer.writePropertyName("timeSignatureDenominator"); + writer.writeNumber(obj.timeSignatureDenominator); + writer.writePropertyName("timeSignatureCommon"); + writer.writeBoolean(obj.timeSignatureCommon); + writer.writePropertyName("tripletFeel"); + writer.writeEnum(obj.tripletFeel); + writer.writePropertyName("section"); + if (obj.section) { + SectionSerializer.toJson(obj.section, writer); } - else { - json.section = SectionSerializer.toJson(obj.section); - } - if (json.tempoAutomation) { - if (obj.tempoAutomation) { - AutomationSerializer.fillToJson(obj.tempoAutomation, json.tempoAutomation); - } + else + writer.writeNull(); + writer.writePropertyName("tempoAutomation"); + if (obj.tempoAutomation) { + AutomationSerializer.toJson(obj.tempoAutomation, writer); } - else { - json.tempoAutomation = AutomationSerializer.toJson(obj.tempoAutomation); - } - json.fermata = ({} as any); - obj.fermata.forEach(($mv, $mk) => { (json.fermata as any)[$mk] = FermataSerializer.toJson($mv); }); - json.start = obj.start; - json.isAnacrusis = obj.isAnacrusis; + else + writer.writeNull(); + writer.writePropertyName("fermata"); + writer.writeStartObject(); + obj.fermata.forEach((k, v) => { writer.writePropertyName(k); FermataSerializer.toJson(m); }); + writer.writeEndObject(); + writer.writePropertyName("start"); + writer.writeNumber(obj.start); + writer.writePropertyName("isAnacrusis"); + writer.writeBoolean(obj.isAnacrusis); + writer.writeEndObject(); } - public static setProperty(obj: MasterBar, property: string, value: any): boolean { + public static setProperty(obj: MasterBar, property: string, reader: IJsonReader): boolean { switch (property) { case "alternateendings": - obj.alternateEndings = value; + obj.alternateEndings = (reader.readNumber()!); return true; case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "keysignature": - obj.keySignature = isNaN(parseInt(value)) ? KeySignature[Object.keys(KeySignature).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof KeySignature] : parseInt(value); + obj.keySignature = (reader.readEnum(KeySignature)!); return true; case "keysignaturetype": - obj.keySignatureType = isNaN(parseInt(value)) ? KeySignatureType[Object.keys(KeySignatureType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof KeySignatureType] : parseInt(value); + obj.keySignatureType = (reader.readEnum(KeySignatureType)!); return true; case "isdoublebar": - obj.isDoubleBar = value; + obj.isDoubleBar = (reader.readBoolean()!); return true; case "isrepeatstart": - obj.isRepeatStart = value; + obj.isRepeatStart = (reader.readBoolean()!); return true; case "repeatcount": - obj.repeatCount = value; + obj.repeatCount = (reader.readNumber()!); return true; case "timesignaturenumerator": - obj.timeSignatureNumerator = value; + obj.timeSignatureNumerator = (reader.readNumber()!); return true; case "timesignaturedenominator": - obj.timeSignatureDenominator = value; + obj.timeSignatureDenominator = (reader.readNumber()!); return true; case "timesignaturecommon": - obj.timeSignatureCommon = value; + obj.timeSignatureCommon = (reader.readBoolean()!); return true; case "tripletfeel": - obj.tripletFeel = isNaN(parseInt(value)) ? TripletFeel[Object.keys(TripletFeel).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof TripletFeel] : parseInt(value); + obj.tripletFeel = (reader.readEnum(TripletFeel)!); return true; case "fermata": obj.fermata = new Map(); - for (let $mk in value) - if (value.hasOwnProperty($mk)) - obj.fermata.set(parseInt($mk), FermataSerializer.fromJson(value[$mk])); + for (let __mk in value) + if (value.hasOwnProperty(__mk)) + obj.fermata.set(parseInt(__mk), FermataSerializer.fromJson(value[__mk])); return true; case "start": - obj.start = value; + obj.start = (reader.readNumber()!); return true; case "isanacrusis": - obj.isAnacrusis = value; + obj.isAnacrusis = (reader.readBoolean()!); return true; } if (["section"].indexOf(property) >= 0) { - if (obj.section) - SectionSerializer.fillFromJson(obj.section, value); - else - obj.section = value ? SectionSerializer.fromJson(value) : null; + if (reader.currentValueType !== JsonValueType.Null) { + obj.section = new Section(); + SectionSerializer.fromJson(obj.section, reader); + } + else { + obj.section = null; + } return true; - } - else { - for (const $c of ["section"]) - if (property.indexOf($c) === 0) { - if (!obj.section) { - obj.section = new Section(); - } - if (SectionSerializer.setProperty(obj.section, property.substring($c.length), value)) { - return true; - } - } } if (["tempoautomation"].indexOf(property) >= 0) { - if (obj.tempoAutomation) - AutomationSerializer.fillFromJson(obj.tempoAutomation, value); - else - obj.tempoAutomation = value ? AutomationSerializer.fromJson(value) : null; + if (reader.currentValueType !== JsonValueType.Null) { + obj.tempoAutomation = new Automation(); + AutomationSerializer.fromJson(obj.tempoAutomation, reader); + } + else { + obj.tempoAutomation = null; + } return true; - } - else { - for (const $c of ["tempoautomation"]) - if (property.indexOf($c) === 0) { - if (!obj.tempoAutomation) { - obj.tempoAutomation = new Automation(); - } - if (AutomationSerializer.setProperty(obj.tempoAutomation, property.substring($c.length), value)) { - return true; - } - } } return false; } diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index 9866d7b36..f8a136cd9 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -4,6 +4,9 @@ // the code is regenerated. // import { Note } from "@src/model/Note"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; import { AccentuationType } from "@src/model/AccentuationType"; import { BendType } from "@src/model/BendType"; @@ -17,203 +20,244 @@ import { Duration } from "@src/model/Duration"; import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; import { DynamicValue } from "@src/model/DynamicValue"; export class NoteSerializer { - public static fromJson(json: any): Note { - const obj = new Note(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Note, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Note, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Note | null): any { + public static toJson(obj: Note | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Note, json: any): void { - json.id = obj.id; - json.index = obj.index; - json.accentuated = obj.accentuated; - json.bendType = obj.bendType; - json.bendStyle = obj.bendStyle; - json.isContinuedBend = obj.isContinuedBend; - json.bendPoints = obj.bendPoints.map($li => BendPointSerializer.toJson($li)); - json.fret = obj.fret; - json.string = obj.string; - json.octave = obj.octave; - json.tone = obj.tone; - json.percussionArticulation = obj.percussionArticulation; - json.isVisible = obj.isVisible; - json.isLeftHandTapped = obj.isLeftHandTapped; - json.isHammerPullOrigin = obj.isHammerPullOrigin; - json.hammerPullOriginNoteId = obj.hammerPullOriginNoteId; - json.hammerPullDestinationNoteId = obj.hammerPullDestinationNoteId; - json.isSlurDestination = obj.isSlurDestination; - json.slurOriginNoteId = obj.slurOriginNoteId; - json.slurDestinationNoteId = obj.slurDestinationNoteId; - json.harmonicType = obj.harmonicType; - json.harmonicValue = obj.harmonicValue; - json.isGhost = obj.isGhost; - json.isLetRing = obj.isLetRing; - json.isPalmMute = obj.isPalmMute; - json.isDead = obj.isDead; - json.isStaccato = obj.isStaccato; - json.slideInType = obj.slideInType; - json.slideOutType = obj.slideOutType; - json.vibrato = obj.vibrato; - json.tieOriginNoteId = obj.tieOriginNoteId; - json.tieDestinationNoteId = obj.tieDestinationNoteId; - json.isTieDestination = obj.isTieDestination; - json.leftHandFinger = obj.leftHandFinger; - json.rightHandFinger = obj.rightHandFinger; - json.isFingering = obj.isFingering; - json.trillValue = obj.trillValue; - json.trillSpeed = obj.trillSpeed; - json.durationPercent = obj.durationPercent; - json.accidentalMode = obj.accidentalMode; - json.dynamics = obj.dynamics; - json.isEffectSlurOrigin = obj.isEffectSlurOrigin; - json.hasEffectSlur = obj.hasEffectSlur; + writer.writeStartObject(); + writer.writePropertyName("id"); + writer.writeNumber(obj.id); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("accentuated"); + writer.writeEnum(obj.accentuated); + writer.writePropertyName("bendType"); + writer.writeEnum(obj.bendType); + writer.writePropertyName("bendStyle"); + writer.writeEnum(obj.bendStyle); + writer.writePropertyName("isContinuedBend"); + writer.writeBoolean(obj.isContinuedBend); + writer.writePropertyName("bendPoints"); + writer.writeStartArray(); + for (const i of obj.bendPoints) { + BendPointSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("fret"); + writer.writeNumber(obj.fret); + writer.writePropertyName("string"); + writer.writeNumber(obj.string); + writer.writePropertyName("octave"); + writer.writeNumber(obj.octave); + writer.writePropertyName("tone"); + writer.writeNumber(obj.tone); + writer.writePropertyName("percussionArticulation"); + writer.writeNumber(obj.percussionArticulation); + writer.writePropertyName("isVisible"); + writer.writeBoolean(obj.isVisible); + writer.writePropertyName("isLeftHandTapped"); + writer.writeBoolean(obj.isLeftHandTapped); + writer.writePropertyName("isHammerPullOrigin"); + writer.writeBoolean(obj.isHammerPullOrigin); + writer.writePropertyName("hammerPullOriginNoteId"); + writer.writeNumber(obj.hammerPullOriginNoteId); + writer.writePropertyName("hammerPullDestinationNoteId"); + writer.writeNumber(obj.hammerPullDestinationNoteId); + writer.writePropertyName("isSlurDestination"); + writer.writeBoolean(obj.isSlurDestination); + writer.writePropertyName("slurOriginNoteId"); + writer.writeNumber(obj.slurOriginNoteId); + writer.writePropertyName("slurDestinationNoteId"); + writer.writeNumber(obj.slurDestinationNoteId); + writer.writePropertyName("harmonicType"); + writer.writeEnum(obj.harmonicType); + writer.writePropertyName("harmonicValue"); + writer.writeNumber(obj.harmonicValue); + writer.writePropertyName("isGhost"); + writer.writeBoolean(obj.isGhost); + writer.writePropertyName("isLetRing"); + writer.writeBoolean(obj.isLetRing); + writer.writePropertyName("isPalmMute"); + writer.writeBoolean(obj.isPalmMute); + writer.writePropertyName("isDead"); + writer.writeBoolean(obj.isDead); + writer.writePropertyName("isStaccato"); + writer.writeBoolean(obj.isStaccato); + writer.writePropertyName("slideInType"); + writer.writeEnum(obj.slideInType); + writer.writePropertyName("slideOutType"); + writer.writeEnum(obj.slideOutType); + writer.writePropertyName("vibrato"); + writer.writeEnum(obj.vibrato); + writer.writePropertyName("tieOriginNoteId"); + writer.writeNumber(obj.tieOriginNoteId); + writer.writePropertyName("tieDestinationNoteId"); + writer.writeNumber(obj.tieDestinationNoteId); + writer.writePropertyName("isTieDestination"); + writer.writeBoolean(obj.isTieDestination); + writer.writePropertyName("leftHandFinger"); + writer.writeEnum(obj.leftHandFinger); + writer.writePropertyName("rightHandFinger"); + writer.writeEnum(obj.rightHandFinger); + writer.writePropertyName("isFingering"); + writer.writeBoolean(obj.isFingering); + writer.writePropertyName("trillValue"); + writer.writeNumber(obj.trillValue); + writer.writePropertyName("trillSpeed"); + writer.writeEnum(obj.trillSpeed); + writer.writePropertyName("durationPercent"); + writer.writeNumber(obj.durationPercent); + writer.writePropertyName("accidentalMode"); + writer.writeEnum(obj.accidentalMode); + writer.writePropertyName("dynamics"); + writer.writeEnum(obj.dynamics); + writer.writePropertyName("isEffectSlurOrigin"); + writer.writeBoolean(obj.isEffectSlurOrigin); + writer.writePropertyName("hasEffectSlur"); + writer.writeBoolean(obj.hasEffectSlur); + writer.writeEndObject(); } - public static setProperty(obj: Note, property: string, value: any): boolean { + public static setProperty(obj: Note, property: string, reader: IJsonReader): boolean { switch (property) { case "id": - obj.id = value; + obj.id = (reader.readNumber()!); return true; case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "accentuated": - obj.accentuated = isNaN(parseInt(value)) ? AccentuationType[Object.keys(AccentuationType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof AccentuationType] : parseInt(value); + obj.accentuated = (reader.readEnum(AccentuationType)!); return true; case "bendtype": - obj.bendType = isNaN(parseInt(value)) ? BendType[Object.keys(BendType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendType] : parseInt(value); + obj.bendType = (reader.readEnum(BendType)!); return true; case "bendstyle": - obj.bendStyle = isNaN(parseInt(value)) ? BendStyle[Object.keys(BendStyle).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof BendStyle] : parseInt(value); + obj.bendStyle = (reader.readEnum(BendStyle)!); return true; case "iscontinuedbend": - obj.isContinuedBend = value; + obj.isContinuedBend = (reader.readBoolean()!); return true; case "bendpoints": obj.bendPoints = []; - for (const $li of value) - obj.bendPoints.push(BendPointSerializer.fromJson($li)); + for (const __li of value) + obj.bendPoints.push(BendPointSerializer.fromJson(i, j)); return true; case "fret": - obj.fret = value; + obj.fret = (reader.readNumber()!); return true; case "string": - obj.string = value; + obj.string = (reader.readNumber()!); return true; case "octave": - obj.octave = value; + obj.octave = (reader.readNumber()!); return true; case "tone": - obj.tone = value; + obj.tone = (reader.readNumber()!); return true; case "percussionarticulation": - obj.percussionArticulation = value; + obj.percussionArticulation = (reader.readNumber()!); return true; case "isvisible": - obj.isVisible = value; + obj.isVisible = (reader.readBoolean()!); return true; case "islefthandtapped": - obj.isLeftHandTapped = value; + obj.isLeftHandTapped = (reader.readBoolean()!); return true; case "ishammerpullorigin": - obj.isHammerPullOrigin = value; + obj.isHammerPullOrigin = (reader.readBoolean()!); return true; case "hammerpulloriginnoteid": - obj.hammerPullOriginNoteId = value; + obj.hammerPullOriginNoteId = (reader.readNumber()!); return true; case "hammerpulldestinationnoteid": - obj.hammerPullDestinationNoteId = value; + obj.hammerPullDestinationNoteId = (reader.readNumber()!); return true; case "isslurdestination": - obj.isSlurDestination = value; + obj.isSlurDestination = (reader.readBoolean()!); return true; case "sluroriginnoteid": - obj.slurOriginNoteId = value; + obj.slurOriginNoteId = (reader.readNumber()!); return true; case "slurdestinationnoteid": - obj.slurDestinationNoteId = value; + obj.slurDestinationNoteId = (reader.readNumber()!); return true; case "harmonictype": - obj.harmonicType = isNaN(parseInt(value)) ? HarmonicType[Object.keys(HarmonicType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof HarmonicType] : parseInt(value); + obj.harmonicType = (reader.readEnum(HarmonicType)!); return true; case "harmonicvalue": - obj.harmonicValue = value; + obj.harmonicValue = (reader.readNumber()!); return true; case "isghost": - obj.isGhost = value; + obj.isGhost = (reader.readBoolean()!); return true; case "isletring": - obj.isLetRing = value; + obj.isLetRing = (reader.readBoolean()!); return true; case "ispalmmute": - obj.isPalmMute = value; + obj.isPalmMute = (reader.readBoolean()!); return true; case "isdead": - obj.isDead = value; + obj.isDead = (reader.readBoolean()!); return true; case "isstaccato": - obj.isStaccato = value; + obj.isStaccato = (reader.readBoolean()!); return true; case "slideintype": - obj.slideInType = isNaN(parseInt(value)) ? SlideInType[Object.keys(SlideInType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SlideInType] : parseInt(value); + obj.slideInType = (reader.readEnum(SlideInType)!); return true; case "slideouttype": - obj.slideOutType = isNaN(parseInt(value)) ? SlideOutType[Object.keys(SlideOutType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof SlideOutType] : parseInt(value); + obj.slideOutType = (reader.readEnum(SlideOutType)!); return true; case "vibrato": - obj.vibrato = isNaN(parseInt(value)) ? VibratoType[Object.keys(VibratoType).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof VibratoType] : parseInt(value); + obj.vibrato = (reader.readEnum(VibratoType)!); return true; case "tieoriginnoteid": - obj.tieOriginNoteId = value; + obj.tieOriginNoteId = (reader.readNumber()!); return true; case "tiedestinationnoteid": - obj.tieDestinationNoteId = value; + obj.tieDestinationNoteId = (reader.readNumber()!); return true; case "istiedestination": - obj.isTieDestination = value; + obj.isTieDestination = (reader.readBoolean()!); return true; case "lefthandfinger": - obj.leftHandFinger = isNaN(parseInt(value)) ? Fingers[Object.keys(Fingers).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Fingers] : parseInt(value); + obj.leftHandFinger = (reader.readEnum(Fingers)!); return true; case "righthandfinger": - obj.rightHandFinger = isNaN(parseInt(value)) ? Fingers[Object.keys(Fingers).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Fingers] : parseInt(value); + obj.rightHandFinger = (reader.readEnum(Fingers)!); return true; case "isfingering": - obj.isFingering = value; + obj.isFingering = (reader.readBoolean()!); return true; case "trillvalue": - obj.trillValue = value; + obj.trillValue = (reader.readNumber()!); return true; case "trillspeed": - obj.trillSpeed = isNaN(parseInt(value)) ? Duration[Object.keys(Duration).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof Duration] : parseInt(value); + obj.trillSpeed = (reader.readEnum(Duration)!); return true; case "durationpercent": - obj.durationPercent = value; + obj.durationPercent = (reader.readNumber()!); return true; case "accidentalmode": - obj.accidentalMode = isNaN(parseInt(value)) ? NoteAccidentalMode[Object.keys(NoteAccidentalMode).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof NoteAccidentalMode] : parseInt(value); + obj.accidentalMode = (reader.readEnum(NoteAccidentalMode)!); return true; case "dynamics": - obj.dynamics = isNaN(parseInt(value)) ? DynamicValue[Object.keys(DynamicValue).find($k => $k.toLowerCase() === value.toLowerCase()) as keyof typeof DynamicValue] : parseInt(value); + obj.dynamics = (reader.readEnum(DynamicValue)!); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = value; + obj.isEffectSlurOrigin = (reader.readBoolean()!); return true; case "haseffectslur": - obj.hasEffectSlur = value; + obj.hasEffectSlur = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts index a1af96c03..b31781a66 100644 --- a/src/generated/model/PlaybackInformationSerializer.ts +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -4,62 +4,67 @@ // the code is regenerated. // import { PlaybackInformation } from "@src/model/PlaybackInformation"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class PlaybackInformationSerializer { - public static fromJson(json: any): PlaybackInformation { - const obj = new PlaybackInformation(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: PlaybackInformation, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: PlaybackInformation, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: PlaybackInformation | null): any { + public static toJson(obj: PlaybackInformation | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: PlaybackInformation, json: any): void { - json.volume = obj.volume; - json.balance = obj.balance; - json.port = obj.port; - json.program = obj.program; - json.primaryChannel = obj.primaryChannel; - json.secondaryChannel = obj.secondaryChannel; - json.isMute = obj.isMute; - json.isSolo = obj.isSolo; + writer.writeStartObject(); + writer.writePropertyName("volume"); + writer.writeNumber(obj.volume); + writer.writePropertyName("balance"); + writer.writeNumber(obj.balance); + writer.writePropertyName("port"); + writer.writeNumber(obj.port); + writer.writePropertyName("program"); + writer.writeNumber(obj.program); + writer.writePropertyName("primaryChannel"); + writer.writeNumber(obj.primaryChannel); + writer.writePropertyName("secondaryChannel"); + writer.writeNumber(obj.secondaryChannel); + writer.writePropertyName("isMute"); + writer.writeBoolean(obj.isMute); + writer.writePropertyName("isSolo"); + writer.writeBoolean(obj.isSolo); + writer.writeEndObject(); } - public static setProperty(obj: PlaybackInformation, property: string, value: any): boolean { + public static setProperty(obj: PlaybackInformation, property: string, reader: IJsonReader): boolean { switch (property) { case "volume": - obj.volume = value; + obj.volume = (reader.readNumber()!); return true; case "balance": - obj.balance = value; + obj.balance = (reader.readNumber()!); return true; case "port": - obj.port = value; + obj.port = (reader.readNumber()!); return true; case "program": - obj.program = value; + obj.program = (reader.readNumber()!); return true; case "primarychannel": - obj.primaryChannel = value; + obj.primaryChannel = (reader.readNumber()!); return true; case "secondarychannel": - obj.secondaryChannel = value; + obj.secondaryChannel = (reader.readNumber()!); return true; case "ismute": - obj.isMute = value; + obj.isMute = (reader.readBoolean()!); return true; case "issolo": - obj.isSolo = value; + obj.isSolo = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts index d74865d1f..b5936c047 100644 --- a/src/generated/model/RenderStylesheetSerializer.ts +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -4,34 +4,32 @@ // the code is regenerated. // import { RenderStylesheet } from "@src/model/RenderStylesheet"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class RenderStylesheetSerializer { - public static fromJson(json: any): RenderStylesheet { - const obj = new RenderStylesheet(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: RenderStylesheet, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: RenderStylesheet, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: RenderStylesheet | null): any { + public static toJson(obj: RenderStylesheet | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: RenderStylesheet, json: any): void { - json.hideDynamics = obj.hideDynamics; + writer.writeStartObject(); + writer.writePropertyName("hideDynamics"); + writer.writeBoolean(obj.hideDynamics); + writer.writeEndObject(); } - public static setProperty(obj: RenderStylesheet, property: string, value: any): boolean { + public static setProperty(obj: RenderStylesheet, property: string, reader: IJsonReader): boolean { switch (property) { case "hidedynamics": - obj.hideDynamics = value; + obj.hideDynamics = (reader.readBoolean()!); return true; } return false; diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index 2201536cf..795662eae 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -4,119 +4,119 @@ // the code is regenerated. // import { Score } from "@src/model/Score"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { MasterBarSerializer } from "@src/generated/model/MasterBarSerializer"; import { TrackSerializer } from "@src/generated/model/TrackSerializer"; import { RenderStylesheetSerializer } from "@src/generated/model/RenderStylesheetSerializer"; -import { RenderStylesheet } from "@src/model/RenderStylesheet"; export class ScoreSerializer { - public static fromJson(json: any): Score { - const obj = new Score(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Score, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Score, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Score | null): any { + public static toJson(obj: Score | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Score, json: any): void { - json.album = obj.album; - json.artist = obj.artist; - json.copyright = obj.copyright; - json.instructions = obj.instructions; - json.music = obj.music; - json.notices = obj.notices; - json.subTitle = obj.subTitle; - json.title = obj.title; - json.words = obj.words; - json.tab = obj.tab; - json.tempo = obj.tempo; - json.tempoLabel = obj.tempoLabel; - json.masterBars = obj.masterBars.map($li => MasterBarSerializer.toJson($li)); - json.tracks = obj.tracks.map($li => TrackSerializer.toJson($li)); - if (json.stylesheet) { - RenderStylesheetSerializer.fillToJson(obj.stylesheet, json.stylesheet); - } - else { - json.stylesheet = (RenderStylesheetSerializer.toJson(obj.stylesheet)!); + writer.writeStartObject(); + writer.writePropertyName("album"); + writer.writeString(obj.album); + writer.writePropertyName("artist"); + writer.writeString(obj.artist); + writer.writePropertyName("copyright"); + writer.writeString(obj.copyright); + writer.writePropertyName("instructions"); + writer.writeString(obj.instructions); + writer.writePropertyName("music"); + writer.writeString(obj.music); + writer.writePropertyName("notices"); + writer.writeString(obj.notices); + writer.writePropertyName("subTitle"); + writer.writeString(obj.subTitle); + writer.writePropertyName("title"); + writer.writeString(obj.title); + writer.writePropertyName("words"); + writer.writeString(obj.words); + writer.writePropertyName("tab"); + writer.writeString(obj.tab); + writer.writePropertyName("tempo"); + writer.writeNumber(obj.tempo); + writer.writePropertyName("tempoLabel"); + writer.writeString(obj.tempoLabel); + writer.writePropertyName("masterBars"); + writer.writeStartArray(); + for (const i of obj.masterBars) { + MasterBarSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("tracks"); + writer.writeStartArray(); + for (const i of obj.tracks) { + TrackSerializer.toJson(i, writer); } + writer.writeEndArray(); + writer.writePropertyName("stylesheet"); + RenderStylesheetSerializer.toJson(obj.stylesheet, writer); + writer.writeEndObject(); } - public static setProperty(obj: Score, property: string, value: any): boolean { + public static setProperty(obj: Score, property: string, reader: IJsonReader): boolean { switch (property) { case "album": - obj.album = value; + obj.album = (reader.readString()!); return true; case "artist": - obj.artist = value; + obj.artist = (reader.readString()!); return true; case "copyright": - obj.copyright = value; + obj.copyright = (reader.readString()!); return true; case "instructions": - obj.instructions = value; + obj.instructions = (reader.readString()!); return true; case "music": - obj.music = value; + obj.music = (reader.readString()!); return true; case "notices": - obj.notices = value; + obj.notices = (reader.readString()!); return true; case "subtitle": - obj.subTitle = value; + obj.subTitle = (reader.readString()!); return true; case "title": - obj.title = value; + obj.title = (reader.readString()!); return true; case "words": - obj.words = value; + obj.words = (reader.readString()!); return true; case "tab": - obj.tab = value; + obj.tab = (reader.readString()!); return true; case "tempo": - obj.tempo = value; + obj.tempo = (reader.readNumber()!); return true; case "tempolabel": - obj.tempoLabel = value; + obj.tempoLabel = (reader.readString()!); return true; case "masterbars": obj.masterBars = []; - for (const $li of value) - obj.addMasterBar(MasterBarSerializer.fromJson($li)); + for (const __li of value) + obj.addMasterBar(MasterBarSerializer.fromJson(i, j)); return true; case "tracks": obj.tracks = []; - for (const $li of value) - obj.addTrack(TrackSerializer.fromJson($li)); + for (const __li of value) + obj.addTrack(TrackSerializer.fromJson(i, j)); return true; } if (["stylesheet"].indexOf(property) >= 0) { - if (obj.stylesheet) - RenderStylesheetSerializer.fillFromJson(obj.stylesheet, value); - else - obj.stylesheet = RenderStylesheetSerializer.fromJson(value); + RenderStylesheetSerializer.fromJson(obj.stylesheet, reader); return true; - } - else { - for (const $c of ["stylesheet"]) - if (property.indexOf($c) === 0) { - if (!obj.stylesheet) { - obj.stylesheet = new RenderStylesheet(); - } - if (RenderStylesheetSerializer.setProperty(obj.stylesheet, property.substring($c.length), value)) { - return true; - } - } } return false; } diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts index 2b7e39b65..848b03993 100644 --- a/src/generated/model/SectionSerializer.ts +++ b/src/generated/model/SectionSerializer.ts @@ -4,38 +4,37 @@ // the code is regenerated. // import { Section } from "@src/model/Section"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; export class SectionSerializer { - public static fromJson(json: any): Section { - const obj = new Section(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Section, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Section, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Section | null): any { + public static toJson(obj: Section | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Section, json: any): void { - json.marker = obj.marker; - json.text = obj.text; + writer.writeStartObject(); + writer.writePropertyName("marker"); + writer.writeString(obj.marker); + writer.writePropertyName("text"); + writer.writeString(obj.text); + writer.writeEndObject(); } - public static setProperty(obj: Section, property: string, value: any): boolean { + public static setProperty(obj: Section, property: string, reader: IJsonReader): boolean { switch (property) { case "marker": - obj.marker = value; + obj.marker = (reader.readString()!); return true; case "text": - obj.text = value; + obj.text = (reader.readString()!); return true; } return false; diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 3be601a9d..a7d4f5f29 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -4,87 +4,101 @@ // the code is regenerated. // import { Staff } from "@src/model/Staff"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { BarSerializer } from "@src/generated/model/BarSerializer"; import { ChordSerializer } from "@src/generated/model/ChordSerializer"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { - public static fromJson(json: any): Staff { - const obj = new Staff(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Staff, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Staff, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Staff | null): any { + public static toJson(obj: Staff | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Staff, json: any): void { - json.index = obj.index; - json.bars = obj.bars.map($li => BarSerializer.toJson($li)); - json.chords = ({} as any); - obj.chords.forEach(($mv, $mk) => { (json.chords as any)[$mk] = ChordSerializer.toJson($mv); }); - json.capo = obj.capo; - json.transpositionPitch = obj.transpositionPitch; - json.displayTranspositionPitch = obj.displayTranspositionPitch; - json.tuning = obj.tuning.slice(); - json.tuningName = obj.tuningName; - json.showTablature = obj.showTablature; - json.showStandardNotation = obj.showStandardNotation; - json.isPercussion = obj.isPercussion; - json.standardNotationLineCount = obj.standardNotationLineCount; + writer.writeStartObject(); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("bars"); + writer.writeStartArray(); + for (const i of obj.bars) { + BarSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("chords"); + writer.writeStartObject(); + obj.chords.forEach((k, v) => { writer.writePropertyName(k); ChordSerializer.toJson(m); }); + writer.writeEndObject(); + writer.writePropertyName("capo"); + writer.writeNumber(obj.capo); + writer.writePropertyName("transpositionPitch"); + writer.writeNumber(obj.transpositionPitch); + writer.writePropertyName("displayTranspositionPitch"); + writer.writeNumber(obj.displayTranspositionPitch); + writer.writePropertyName("tuning"); + writer.writeNumberArray(obj.tuning); + writer.writePropertyName("tuningName"); + writer.writeString(obj.tuningName); + writer.writePropertyName("showTablature"); + writer.writeBoolean(obj.showTablature); + writer.writePropertyName("showStandardNotation"); + writer.writeBoolean(obj.showStandardNotation); + writer.writePropertyName("isPercussion"); + writer.writeBoolean(obj.isPercussion); + writer.writePropertyName("standardNotationLineCount"); + writer.writeNumber(obj.standardNotationLineCount); + writer.writeEndObject(); } - public static setProperty(obj: Staff, property: string, value: any): boolean { + public static setProperty(obj: Staff, property: string, reader: IJsonReader): boolean { switch (property) { case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "bars": obj.bars = []; - for (const $li of value) - obj.addBar(BarSerializer.fromJson($li)); + for (const __li of value) + obj.addBar(BarSerializer.fromJson(i, j)); return true; case "chords": obj.chords = new Map(); - for (let $mk in value) - if (value.hasOwnProperty($mk)) - obj.addChord($mk, ChordSerializer.fromJson(value[$mk])); + for (let __mk in value) + if (value.hasOwnProperty(__mk)) + obj.addChord(__mk, ChordSerializer.fromJson(value[__mk])); return true; case "capo": - obj.capo = value; + obj.capo = (reader.readNumber()!); return true; case "transpositionpitch": - obj.transpositionPitch = value; + obj.transpositionPitch = (reader.readNumber()!); return true; case "displaytranspositionpitch": - obj.displayTranspositionPitch = value; + obj.displayTranspositionPitch = (reader.readNumber()!); return true; case "tuning": - obj.tuning = value.slice(); + obj.tuning = (reader.readNumberArray()!); return true; case "tuningname": - obj.tuningName = value; + obj.tuningName = (reader.readString()!); return true; case "showtablature": - obj.showTablature = value; + obj.showTablature = (reader.readBoolean()!); return true; case "showstandardnotation": - obj.showStandardNotation = value; + obj.showStandardNotation = (reader.readBoolean()!); return true; case "ispercussion": - obj.isPercussion = value; + obj.isPercussion = (reader.readBoolean()!); return true; case "standardnotationlinecount": - obj.standardNotationLineCount = value; + obj.standardNotationLineCount = (reader.readNumber()!); return true; } return false; diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index e86a6d6f4..634f374fa 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -4,88 +4,80 @@ // the code is regenerated. // import { Track } from "@src/model/Track"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { StaffSerializer } from "@src/generated/model/StaffSerializer"; import { PlaybackInformationSerializer } from "@src/generated/model/PlaybackInformationSerializer"; import { Color } from "@src/model/Color"; import { InstrumentArticulationSerializer } from "@src/generated/model/InstrumentArticulationSerializer"; -import { PlaybackInformation } from "@src/model/PlaybackInformation"; export class TrackSerializer { - public static fromJson(json: any): Track { - const obj = new Track(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Track, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Track, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Track | null): any { + public static toJson(obj: Track | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Track, json: any): void { - json.index = obj.index; - json.staves = obj.staves.map($li => StaffSerializer.toJson($li)); - if (json.playbackInfo) { - PlaybackInformationSerializer.fillToJson(obj.playbackInfo, json.playbackInfo); - } - else { - json.playbackInfo = (PlaybackInformationSerializer.toJson(obj.playbackInfo)!); + writer.writeStartObject(); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("staves"); + writer.writeStartArray(); + for (const i of obj.staves) { + StaffSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("playbackInfo"); + PlaybackInformationSerializer.toJson(obj.playbackInfo, writer); + writer.writePropertyName("color"); + Color.toJson(obj.color, writer); + writer.writePropertyName("name"); + writer.writeString(obj.name); + writer.writePropertyName("shortName"); + writer.writeString(obj.shortName); + writer.writePropertyName("percussionArticulations"); + writer.writeStartArray(); + for (const i of obj.percussionArticulations) { + InstrumentArticulationSerializer.toJson(i, writer); } - json.color = (Color.toJson(obj.color)!); - json.name = obj.name; - json.shortName = obj.shortName; - json.percussionArticulations = obj.percussionArticulations.map($li => InstrumentArticulationSerializer.toJson($li)); + writer.writeEndArray(); + writer.writeEndObject(); } - public static setProperty(obj: Track, property: string, value: any): boolean { + public static setProperty(obj: Track, property: string, reader: IJsonReader): boolean { switch (property) { case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "staves": obj.staves = []; - for (const $li of value) - obj.addStaff(StaffSerializer.fromJson($li)); + for (const __li of value) + obj.addStaff(StaffSerializer.fromJson(i, j)); return true; case "color": obj.color = (Color.fromJson(value)!); return true; case "name": - obj.name = value; + obj.name = (reader.readString()!); return true; case "shortname": - obj.shortName = value; + obj.shortName = (reader.readString()!); return true; case "percussionarticulations": obj.percussionArticulations = []; - for (const $li of value) - obj.percussionArticulations.push(InstrumentArticulationSerializer.fromJson($li)); + for (const __li of value) + obj.percussionArticulations.push(InstrumentArticulationSerializer.fromJson(i, j)); return true; } if (["playbackinfo"].indexOf(property) >= 0) { - if (obj.playbackInfo) - PlaybackInformationSerializer.fillFromJson(obj.playbackInfo, value); - else - obj.playbackInfo = PlaybackInformationSerializer.fromJson(value); + PlaybackInformationSerializer.fromJson(obj.playbackInfo, reader); return true; - } - else { - for (const $c of ["playbackinfo"]) - if (property.indexOf($c) === 0) { - if (!obj.playbackInfo) { - obj.playbackInfo = new PlaybackInformation(); - } - if (PlaybackInformationSerializer.setProperty(obj.playbackInfo, property.substring($c.length), value)) { - return true; - } - } } return false; } diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index a7888e7e6..c4cd43df1 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -4,45 +4,49 @@ // the code is regenerated. // import { Voice } from "@src/model/Voice"; +import { IJsonReader } from "@src/io/IJsonReader"; +import { JsonValueType } from "@src/io/IJsonReader"; +import { IJsonWriter } from "@src/io/IJsonWriter"; import { BeatSerializer } from "@src/generated/model/BeatSerializer"; export class VoiceSerializer { - public static fromJson(json: any): Voice { - const obj = new Voice(); - this.fillFromJson(obj, json); - return obj; - } - public static fillFromJson(obj: Voice, json: any): void { - if (json) { - for (const $k in json) { - this.setProperty(obj, $k.toLowerCase(), json[$k]); - } + public static fromJson(obj: Voice, reader: IJsonReader): void { + if (reader.currentValueType !== JsonValueType.Object) { + return; + } + while (reader.nextProperty()) { + this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); } } - public static toJson(obj: Voice | null): any { + public static toJson(obj: Voice | null, writer: IJsonWriter): void { if (!obj) { - return null; + writer.writeNull(); + return; } - const json: any = {}; - this.fillToJson(obj, json); - return json; - } - public static fillToJson(obj: Voice, json: any): void { - json.index = obj.index; - json.beats = obj.beats.map($li => BeatSerializer.toJson($li)); - json.isEmpty = obj.isEmpty; + writer.writeStartObject(); + writer.writePropertyName("index"); + writer.writeNumber(obj.index); + writer.writePropertyName("beats"); + writer.writeStartArray(); + for (const i of obj.beats) { + BeatSerializer.toJson(i, writer); + } + writer.writeEndArray(); + writer.writePropertyName("isEmpty"); + writer.writeBoolean(obj.isEmpty); + writer.writeEndObject(); } - public static setProperty(obj: Voice, property: string, value: any): boolean { + public static setProperty(obj: Voice, property: string, reader: IJsonReader): boolean { switch (property) { case "index": - obj.index = value; + obj.index = (reader.readNumber()!); return true; case "beats": obj.beats = []; - for (const $li of value) - obj.addBeat(BeatSerializer.fromJson($li)); + for (const __li of value) + obj.addBeat(BeatSerializer.fromJson(i, j)); return true; case "isempty": - obj.isEmpty = value; + obj.isEmpty = (reader.readBoolean()!); return true; } return false; diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts new file mode 100644 index 000000000..c006beb57 --- /dev/null +++ b/src/io/IJsonReader.ts @@ -0,0 +1,34 @@ +export enum JsonValueType { + String, + Number, + Boolean, + Null, + Object +} + +export interface IJsonReader { + readonly currentProperty: string; + readonly currentValueType: JsonValueType; + + readPropertyName(): string; + nextProperty(): boolean; + + readString(): string | null; + readEnum(enumType: any): T | null; + readNumber(): number | null; + readBoolean(): boolean | null; + + readStringArray(): string[] | null; + readEnumArray(enumType: any): T[] | null; + readNumberArray(): number[] | null; + readBooleanArray(): boolean[] | null; + + readUint8Array(): Uint8Array | null; + readUint16Array(): Uint16Array | null; + readUint32Array(): Uint32Array | null; + readInt8Array(): Int8Array | null; + readInt16Array(): Int16Array | null; + readInt32Array(): Int32Array | null; + readFloat32Array(): Float32Array | null; + readFloat64Array(): Float64Array | null; +} \ No newline at end of file diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts new file mode 100644 index 000000000..936f229c4 --- /dev/null +++ b/src/io/IJsonWriter.ts @@ -0,0 +1,27 @@ +export interface IJsonWriter { + writeStartObject(): void; + writeEndObject(): void; + + writeStartArray(): void; + writeEndArray(): void; + + writePropertyName(name: string): void; + + writeString(value: string | null): void; + writeNumber(value: number | null): void; + writeBoolean(value: boolean | null): void; + writeEnum(value: T): void; + writeNull(): void; + writeStringArray(value: string[] | null): void; + writeNumberArray(value: number[] | null): void; + writeBooleanArray(value: boolean[] | null): void; + + writeUint8Array(value: Uint8Array | null): void; + writeUint16Array(value: Uint16Array | null): void; + writeUint32Array(value: Uint32Array | null): void; + writeInt8Array(value: Int8Array | null): void; + writeInt16Array(value: Int16Array | null): void; + writeInt32Array(value: Int32Array | null): void; + writeFloat32Array(value: Float32Array | null): void; + writeFloat64Array(value: Float64Array | null): void; +} \ No newline at end of file diff --git a/src/model/Bar.ts b/src/model/Bar.ts index ae0ab2b66..f72095e4b 100644 --- a/src/model/Bar.ts +++ b/src/model/Bar.ts @@ -6,10 +6,6 @@ import { Staff } from '@src/model/Staff'; import { Voice } from '@src/model/Voice'; import { Settings } from '@src/Settings'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -Voice; - /** * A bar is a single block within a track, also known as Measure. * @json diff --git a/src/model/Beat.ts b/src/model/Beat.ts index bf83f6f90..4ead01f3d 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -23,13 +23,6 @@ import { Logger } from '@src/Logger'; import { BeamDirection } from '@src/rendering/utils/BeamDirection'; import { BeatCloner } from '@src/generated/model/BeatCloner'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -Note; -Automation; -BendPoint; -Fermata; - /** * Lists the different modes on how beaming for a beat should be done. */ diff --git a/src/model/Color.ts b/src/model/Color.ts index 2e41f7c7a..80ad2aa8f 100644 --- a/src/model/Color.ts +++ b/src/model/Color.ts @@ -62,9 +62,6 @@ export class Color { return new Color((Math.random() * 255) | 0, (Math.random() * 255) | 0, (Math.random() * 255) | 0, opacity); } - /** - * @target web - */ public static fromJson(json: unknown): Color | null { if (!json) { return null; @@ -145,9 +142,6 @@ export class Color { throw new FormatError('Unsupported format for color'); } - /** - * @target web - */ public static toJson(obj: Color): unknown { return obj.raw; } diff --git a/src/model/Font.ts b/src/model/Font.ts index 1504d87b3..e2c2dd04c 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -79,9 +79,6 @@ export class Font { return this._css; } - /** - * @target web - */ public static fromJson(value: unknown): Font | null { if (!value) { return null; @@ -172,9 +169,6 @@ export class Font { return null; } - /** - * @target web - */ public static toJson(font: Font): unknown { return { family: font.family, diff --git a/src/model/MasterBar.ts b/src/model/MasterBar.ts index 6ad4cef86..0fd037e12 100644 --- a/src/model/MasterBar.ts +++ b/src/model/MasterBar.ts @@ -9,10 +9,6 @@ import { Score } from '@src/model/Score'; import { Section } from '@src/model/Section'; import { TripletFeel } from '@src/model/TripletFeel'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -Fermata; - /** * The MasterBar stores information about a bar which affects * all tracks. diff --git a/src/model/Note.ts b/src/model/Note.ts index 59d3583d7..6b82dcc50 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -21,10 +21,6 @@ import { ModelUtils } from '@src/model/ModelUtils'; import { PickStroke } from './PickStroke'; import { PercussionMapper } from '@src/model/PercussionMapper'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -BendPoint; - /** * A note is a single played sound on a fretted instrument. * It consists of a fret offset and a string on which the note is played on. diff --git a/src/model/Score.ts b/src/model/Score.ts index 2f392d4b3..2baadc108 100644 --- a/src/model/Score.ts +++ b/src/model/Score.ts @@ -5,12 +5,6 @@ import { Track } from '@src/model/Track'; import { Settings } from '@src/Settings'; import { Note } from './Note'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -MasterBar; -RenderStylesheet; -Track; - /** * The score is the root node of the complete * model. It stores the basic information of diff --git a/src/model/Staff.ts b/src/model/Staff.ts index a1a3ec511..d38b205ac 100644 --- a/src/model/Staff.ts +++ b/src/model/Staff.ts @@ -3,11 +3,6 @@ import { Chord } from '@src/model/Chord'; import { Track } from '@src/model/Track'; import { Settings } from '@src/Settings'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -Bar; -Chord; - /** * This class describes a single staff within a track. There are instruments like pianos * where a single track can contain multiple staffs. diff --git a/src/model/Track.ts b/src/model/Track.ts index 02cecb00e..f29c368c6 100644 --- a/src/model/Track.ts +++ b/src/model/Track.ts @@ -7,10 +7,6 @@ import { Staff } from '@src/model/Staff'; import { Settings } from '@src/Settings'; import { InstrumentArticulation } from './InstrumentArticulation'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -InstrumentArticulation; - /** * This public class describes a single track or instrument of score. * It is bascially a list of staffs containing individual music notation kinds. diff --git a/src/model/Voice.ts b/src/model/Voice.ts index 9fb32f283..67c8e8fba 100644 --- a/src/model/Voice.ts +++ b/src/model/Voice.ts @@ -5,10 +5,6 @@ import { Duration } from '@src/model/Duration'; import { GraceType } from '@src/model/GraceType'; import { Settings } from '@src/Settings'; -// TODO: TypeScript optimizes away (elides) some types if they are not used in any expression -// the AST transformer reference is not respected so we add one manually -Beat; - /** * A voice represents a group of beats * that can be played during a bar. diff --git a/src/util/JsonHelper.ts b/src/util/JsonHelper.ts new file mode 100644 index 000000000..2cf95651b --- /dev/null +++ b/src/util/JsonHelper.ts @@ -0,0 +1,8 @@ +export class JsonHelper { + public static parseEnum(value: string, enumType: any): T { + return (isNaN(parseInt(value)) + ? enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] + : parseInt(value) + ) as any as T; + } +} \ No newline at end of file From 15e241dc00282ab2fd5a0d402c6c387615935be9 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 19 Dec 2020 23:22:06 +0100 Subject: [PATCH 09/19] New serialization via reader/writer --- src.compiler/typescript/SerializerEmitter.ts | 242 +++++++++++------- src/Settings.ts | 4 +- src/generated/NotationSettingsSerializer.ts | 8 +- src/generated/RenderingResourcesSerializer.ts | 34 +-- src/generated/model/BarSerializer.ts | 8 +- src/generated/model/BeatSerializer.ts | 24 +- src/generated/model/MasterBarSerializer.ts | 10 +- src/generated/model/NoteSerializer.ts | 8 +- src/generated/model/ScoreSerializer.ts | 16 +- src/generated/model/StaffSerializer.ts | 18 +- src/generated/model/TrackSerializer.ts | 18 +- src/generated/model/VoiceSerializer.ts | 8 +- src/io/IJsonReader.ts | 4 + src/io/IJsonWriter.ts | 2 +- src/model/Color.ts | 152 +++++------ src/model/Font.ts | 197 +++++++------- src/model/JsonConverter.ts | 8 +- src/platform/javascript/AlphaTabWebWorker.ts | 6 +- .../javascript/AlphaTabWorkerScoreRenderer.ts | 3 +- src/platform/javascript/BrowserUiFacade.ts | 4 +- 20 files changed, 452 insertions(+), 322 deletions(-) diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index fb1cf8fd0..d94afb4b0 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -16,6 +16,7 @@ import { isMap } from '../BuilderHelpers'; import { isEnumType } from '../BuilderHelpers'; import { isNumberType } from '../BuilderHelpers'; import { wrapToNonNull } from '../BuilderHelpers'; +import { arrayify } from 'tslint/lib/utils'; interface JsonProperty { partialNames: boolean; @@ -316,14 +317,24 @@ function generateToJsonBody( let writeValue: ts.Expression; if (isPrimitiveType(mapType.typeArguments![1])) { itemSerializer = ''; - writeValue = ts.factory.createIdentifier('v'); + writeValue = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('writer'), + getWriteMethodNameForPrimitive(mapType.typeArguments![1], typeChecker)! + ), + undefined, + [ts.factory.createIdentifier('v')] + ); } else { itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); writeValue = ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), undefined, - [ts.factory.createIdentifier('m')] + [ + ts.factory.createIdentifier('v'), + ts.factory.createIdentifier('writer') + ] ); } @@ -342,8 +353,8 @@ function generateToJsonBody( undefined, undefined, [ - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k'), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v') + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), @@ -560,7 +571,7 @@ function generateSetPropertyBody(program: ts.Program, const read = ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier('reader'), - getReadMethodNameForPrimitive(type.type!, typeChecker)! + primitiveRead ), undefined, [] @@ -599,50 +610,65 @@ function generateSetPropertyBody(program: ts.Program, let itemSerializer = arrayItemType.symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); - - const itemFromJson = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), - [], - [ - ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('j') - ] - ); + importer(arrayItemType.symbol.name, findModule(arrayItemType, program.getCompilerOptions())); const loopItems = [ assignField(ts.factory.createArrayLiteralExpression(undefined)), - ts.factory.createForOfStatement( - undefined, - ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration('__li')], - ts.NodeFlags.Const + ts.factory.createWhileStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextArrayItem'), + undefined, + [] ), - ts.factory.createIdentifier('value'), - ts.factory.createExpressionStatement( - collectionAddMethod - // obj.addFieldName(ItemTypeSerializer.FromJson(__li)) - ? ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('obj'), - collectionAddMethod - ), - undefined, - [itemFromJson] - ) - // obj.fieldName.push(ItemTypeSerializer.FromJson(__li)) - : ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( + ts.factory.createBlock([ + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration('i', + undefined, + undefined, + ts.factory.createNewExpression( + ts.factory.createIdentifier(arrayItemType.symbol.name), + undefined, + [] + )) + ], ts.NodeFlags.Const) + ), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), + undefined, + [ + ts.factory.createIdentifier('i'), + ts.factory.createIdentifier('reader') + ] + ), + ts.factory.createExpressionStatement( + collectionAddMethod + // obj.addFieldName(i) + ? ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier('obj'), - fieldName + collectionAddMethod ), - 'push' - ), - undefined, - [itemFromJson] - ) - ) - )]; + undefined, + [ts.factory.createIdentifier('i')] + ) + // obj.fieldName.push(i) + : ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('obj'), + fieldName + ), + 'push' + ), + undefined, + [ts.factory.createIdentifier('i')] + ) + ) + ].filter(s => !!s) as ts.Statement[]) + ) + ]; if (type.isNullable) { caseStatements.push(ts.factory.createIfStatement( @@ -655,47 +681,50 @@ function generateSetPropertyBody(program: ts.Program, caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isMap(type.type)) { - // this.fieldName = new Map(); - // for(let key in value) { - // if(value.hasOwnProperty(key) obj.fieldName.set(, value[key]); - // } - // or - // for(let key in value) { - // if(value.hasOwnProperty(key) obj.addFieldName(, value[key]); - // } - // return true; - const mapType = type.type as ts.TypeReference; if (!isPrimitiveType(mapType.typeArguments![0])) { throw new Error('only Map maps are supported extend if needed!'); } - const mapKey = isEnumType(mapType.typeArguments![0]) - ? createEnumMapping(mapType.typeArguments![0]) - : isNumberType(mapType.typeArguments![0]) - ? ts.factory.createCallExpression( - ts.factory.createIdentifier('parseInt'), - undefined, - [ts.factory.createIdentifier('__mk')] - ) - : ts.factory.createIdentifier('__mk'); - + let mapKey; if (isEnumType(mapType.typeArguments![0])) { importer(mapType.typeArguments![0].symbol!.name, findModule(mapType.typeArguments![0], program.getCompilerOptions())); + mapKey = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyNameAsEnum'), + [ts.factory.createTypeReferenceNode(mapType.typeArguments![0].symbol!.name)], + [ts.factory.createIdentifier(mapType.typeArguments![0].symbol!.name)] + ); + } else if (isNumberType(mapType.typeArguments![0])) { + mapKey = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyNameAsNumber'), + undefined, + [] + ); + } else { + mapKey = ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyName'), + undefined, + [] + ); } - let mapValue: ts.Expression = ts.factory.createElementAccessExpression(ts.factory.createIdentifier('value'), ts.factory.createIdentifier('__mk')); + let mapValue; let itemSerializer: string = ''; - if (!isPrimitiveType(mapType.typeArguments![1])) { + const primitiveReadForValue = getReadMethodNameForPrimitive(mapType.typeArguments![1], typeChecker); + if (primitiveReadForValue) { + mapValue = ts.factory.createNonNullExpression(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('reader'), + primitiveReadForValue + ), + undefined, + [] + )); + } else { itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); importer(mapType.typeArguments![1]!.symbol.name, findModule(mapType.typeArguments![1], program.getCompilerOptions())); - mapValue = ts.factory.createCallExpression( - // TypeName.fromJson - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), - [], - [mapValue] - ); + mapValue = ts.factory.createIdentifier('i'); } const collectionAddMethod = ts.getJSDocTags(prop.property) @@ -706,37 +735,54 @@ function generateSetPropertyBody(program: ts.Program, typeChecker.typeToTypeNode(mapType.typeArguments![0], undefined, undefined)!, typeChecker.typeToTypeNode(mapType.typeArguments![1], undefined, undefined)!, ], []))); - caseStatements.push( - ts.factory.createForInStatement( - ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration(ts.factory.createIdentifier('__mk'), undefined, undefined)], - ts.NodeFlags.Let + + + caseStatements.push(ts.factory.createWhileStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextProperty'), + undefined, + [] + ), + ts.factory.createBlock([ + !primitiveReadForValue && ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration('i', + undefined, undefined, + ts.factory.createNewExpression(ts.factory.createIdentifier(mapType.typeArguments![1].symbol.name), undefined, []) + ) + ], ts.NodeFlags.Const), ), - ts.factory.createIdentifier('value'), - ts.factory.createIfStatement( + !primitiveReadForValue && ts.factory.createExpressionStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('value'), 'hasOwnProperty'), + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(itemSerializer), + 'fromJson' + ), undefined, - [ts.factory.createIdentifier('__mk')] - ), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - collectionAddMethod - ? ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), collectionAddMethod) - : ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)), - ts.factory.createIdentifier('set') - ), - undefined, - [ - mapKey, - mapValue - ] - ) + [ + ts.factory.createIdentifier('i'), + ts.factory.createIdentifier('reader'), + ] + ) + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + collectionAddMethod + ? ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), collectionAddMethod) + : ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)), + ts.factory.createIdentifier('set') + ), + undefined, + [ + mapKey, + mapValue + ] ) ) - ) - ); + ].filter(s => !!s) as ts.Statement[]) + )); caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isImmutable(type.type)) { let itemSerializer = type.type.symbol.name; @@ -752,7 +798,9 @@ function generateSetPropertyBody(program: ts.Program, // TypeName.fromJson ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), [], - [ts.factory.createIdentifier('value')] + [ + ts.factory.createIdentifier('reader') + ] ), ts.factory ) diff --git a/src/Settings.ts b/src/Settings.ts index f17b3ea09..803aa480f 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -3,7 +3,6 @@ import { DisplaySettings } from '@src/DisplaySettings'; import { ImporterSettings } from '@src/ImporterSettings'; import { FingeringMode, NotationMode, NotationSettings, NotationElement } from '@src/NotationSettings'; import { PlayerSettings } from '@src/PlayerSettings'; -import { SettingsSerializer } from './generated/SettingsSerializer'; /** * This public class contains instance specific settings for alphaTab @@ -15,7 +14,8 @@ export class Settings { */ public fillFromDataAttributes(dataAttributes: Map): void { dataAttributes.forEach((v, k) => { - SettingsSerializer.setProperty(this, k.toLowerCase(), v); + // TODO: replace data attribute settings + // SettingsSerializer.setProperty(this, k.toLowerCase(), v); }); } diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 576cfe3b1..4bf715adc 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -32,7 +32,7 @@ export class NotationSettingsSerializer { writer.writeEnum(obj.fingeringMode); writer.writePropertyName("elements"); writer.writeStartObject(); - obj.elements.forEach((k, v) => { writer.writePropertyName(k); v; }); + obj.elements.forEach((v, k) => { writer.writePropertyName(k); writer.writeBoolean(v); }); writer.writeEndObject(); writer.writePropertyName("rhythmMode"); writer.writeEnum(obj.rhythmMode); @@ -62,9 +62,9 @@ export class NotationSettingsSerializer { return true; case "elements": obj.elements = new Map(); - for (let __mk in value) - if (value.hasOwnProperty(__mk)) - obj.elements.set(reader.readEnum(NotationElement), value[__mk]); + while (reader.nextProperty()) { + obj.elements.set(reader.readPropertyNameAsEnum(NotationElement), (reader.readBoolean()!)); + } return true; case "rhythmmode": obj.rhythmMode = (reader.readEnum(TabRhythmMode)!); diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index d3052657e..2457546fe 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -63,55 +63,55 @@ export class RenderingResourcesSerializer { public static setProperty(obj: RenderingResources, property: string, reader: IJsonReader): boolean { switch (property) { case "copyrightfont": - obj.copyrightFont = (Font.fromJson(value)!); + obj.copyrightFont = (Font.fromJson(reader)!); return true; case "titlefont": - obj.titleFont = (Font.fromJson(value)!); + obj.titleFont = (Font.fromJson(reader)!); return true; case "subtitlefont": - obj.subTitleFont = (Font.fromJson(value)!); + obj.subTitleFont = (Font.fromJson(reader)!); return true; case "wordsfont": - obj.wordsFont = (Font.fromJson(value)!); + obj.wordsFont = (Font.fromJson(reader)!); return true; case "effectfont": - obj.effectFont = (Font.fromJson(value)!); + obj.effectFont = (Font.fromJson(reader)!); return true; case "fretboardnumberfont": - obj.fretboardNumberFont = (Font.fromJson(value)!); + obj.fretboardNumberFont = (Font.fromJson(reader)!); return true; case "tablaturefont": - obj.tablatureFont = (Font.fromJson(value)!); + obj.tablatureFont = (Font.fromJson(reader)!); return true; case "gracefont": - obj.graceFont = (Font.fromJson(value)!); + obj.graceFont = (Font.fromJson(reader)!); return true; case "stafflinecolor": - obj.staffLineColor = (Color.fromJson(value)!); + obj.staffLineColor = (Color.fromJson(reader)!); return true; case "barseparatorcolor": - obj.barSeparatorColor = (Color.fromJson(value)!); + obj.barSeparatorColor = (Color.fromJson(reader)!); return true; case "barnumberfont": - obj.barNumberFont = (Font.fromJson(value)!); + obj.barNumberFont = (Font.fromJson(reader)!); return true; case "barnumbercolor": - obj.barNumberColor = (Color.fromJson(value)!); + obj.barNumberColor = (Color.fromJson(reader)!); return true; case "fingeringfont": - obj.fingeringFont = (Font.fromJson(value)!); + obj.fingeringFont = (Font.fromJson(reader)!); return true; case "markerfont": - obj.markerFont = (Font.fromJson(value)!); + obj.markerFont = (Font.fromJson(reader)!); return true; case "mainglyphcolor": - obj.mainGlyphColor = (Color.fromJson(value)!); + obj.mainGlyphColor = (Color.fromJson(reader)!); return true; case "secondaryglyphcolor": - obj.secondaryGlyphColor = (Color.fromJson(value)!); + obj.secondaryGlyphColor = (Color.fromJson(reader)!); return true; case "scoreinfocolor": - obj.scoreInfoColor = (Color.fromJson(value)!); + obj.scoreInfoColor = (Color.fromJson(reader)!); return true; } return false; diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index aaca6ca16..d6405ab4e 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -10,6 +10,7 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { VoiceSerializer } from "@src/generated/model/VoiceSerializer"; import { Clef } from "@src/model/Clef"; import { Ottavia } from "@src/model/Ottavia"; +import { Voice } from "@src/model/Voice"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { public static fromJson(obj: Bar, reader: IJsonReader): void { @@ -60,8 +61,11 @@ export class BarSerializer { return true; case "voices": obj.voices = []; - for (const __li of value) - obj.addVoice(VoiceSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Voice(); + VoiceSerializer.fromJson(i, reader) + obj.addVoice(i); + } return true; case "similemark": obj.simileMark = (reader.readEnum(SimileMark)!); diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index a8653b542..3517416ba 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -10,11 +10,14 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { NoteSerializer } from "@src/generated/model/NoteSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; +import { Note } from "@src/model/Note"; import { BendStyle } from "@src/model/BendStyle"; import { Ottavia } from "@src/model/Ottavia"; import { Duration } from "@src/model/Duration"; +import { Automation } from "@src/model/Automation"; import { BrushType } from "@src/model/BrushType"; import { WhammyType } from "@src/model/WhammyType"; +import { BendPoint } from "@src/model/BendPoint"; import { VibratoType } from "@src/model/VibratoType"; import { GraceType } from "@src/model/GraceType"; import { PickStroke } from "@src/model/PickStroke"; @@ -143,8 +146,11 @@ export class BeatSerializer { return true; case "notes": obj.notes = []; - for (const __li of value) - obj.addNote(NoteSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Note(); + NoteSerializer.fromJson(i, reader) + obj.addNote(i); + } return true; case "isempty": obj.isEmpty = (reader.readBoolean()!); @@ -169,8 +175,11 @@ export class BeatSerializer { return true; case "automations": obj.automations = []; - for (const __li of value) - obj.automations.push(AutomationSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Automation(); + AutomationSerializer.fromJson(i, reader) + obj.automations.push(i); + } return true; case "dots": obj.dots = (reader.readNumber()!); @@ -216,8 +225,11 @@ export class BeatSerializer { return true; case "whammybarpoints": obj.whammyBarPoints = []; - for (const __li of value) - obj.addWhammyBarPoint(BendPointSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new BendPoint(); + BendPointSerializer.fromJson(i, reader) + obj.addWhammyBarPoint(i); + } return true; case "vibrato": obj.vibrato = (reader.readEnum(VibratoType)!); diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index dbcd616dc..3ce550977 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -67,7 +67,7 @@ export class MasterBarSerializer { writer.writeNull(); writer.writePropertyName("fermata"); writer.writeStartObject(); - obj.fermata.forEach((k, v) => { writer.writePropertyName(k); FermataSerializer.toJson(m); }); + obj.fermata.forEach((v, k) => { writer.writePropertyName(k); FermataSerializer.toJson(v, writer); }); writer.writeEndObject(); writer.writePropertyName("start"); writer.writeNumber(obj.start); @@ -112,9 +112,11 @@ export class MasterBarSerializer { return true; case "fermata": obj.fermata = new Map(); - for (let __mk in value) - if (value.hasOwnProperty(__mk)) - obj.fermata.set(parseInt(__mk), FermataSerializer.fromJson(value[__mk])); + while (reader.nextProperty()) { + const i = new Fermata(); + FermataSerializer.fromJson(i, reader); + obj.fermata.set(reader.readPropertyNameAsNumber(), i); + } return true; case "start": obj.start = (reader.readNumber()!); diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index f8a136cd9..a91e1193c 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -11,6 +11,7 @@ import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; import { AccentuationType } from "@src/model/AccentuationType"; import { BendType } from "@src/model/BendType"; import { BendStyle } from "@src/model/BendStyle"; +import { BendPoint } from "@src/model/BendPoint"; import { HarmonicType } from "@src/model/HarmonicType"; import { SlideInType } from "@src/model/SlideInType"; import { SlideOutType } from "@src/model/SlideOutType"; @@ -148,8 +149,11 @@ export class NoteSerializer { return true; case "bendpoints": obj.bendPoints = []; - for (const __li of value) - obj.bendPoints.push(BendPointSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new BendPoint(); + BendPointSerializer.fromJson(i, reader) + obj.bendPoints.push(i); + } return true; case "fret": obj.fret = (reader.readNumber()!); diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index 795662eae..a93c0594f 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -10,6 +10,8 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { MasterBarSerializer } from "@src/generated/model/MasterBarSerializer"; import { TrackSerializer } from "@src/generated/model/TrackSerializer"; import { RenderStylesheetSerializer } from "@src/generated/model/RenderStylesheetSerializer"; +import { MasterBar } from "@src/model/MasterBar"; +import { Track } from "@src/model/Track"; export class ScoreSerializer { public static fromJson(obj: Score, reader: IJsonReader): void { if (reader.currentValueType !== JsonValueType.Object) { @@ -105,13 +107,19 @@ export class ScoreSerializer { return true; case "masterbars": obj.masterBars = []; - for (const __li of value) - obj.addMasterBar(MasterBarSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new MasterBar(); + MasterBarSerializer.fromJson(i, reader) + obj.addMasterBar(i); + } return true; case "tracks": obj.tracks = []; - for (const __li of value) - obj.addTrack(TrackSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Track(); + TrackSerializer.fromJson(i, reader) + obj.addTrack(i); + } return true; } if (["stylesheet"].indexOf(property) >= 0) { diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index a7d4f5f29..5741fc6f8 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -9,6 +9,7 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { BarSerializer } from "@src/generated/model/BarSerializer"; import { ChordSerializer } from "@src/generated/model/ChordSerializer"; +import { Bar } from "@src/model/Bar"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { public static fromJson(obj: Staff, reader: IJsonReader): void { @@ -35,7 +36,7 @@ export class StaffSerializer { writer.writeEndArray(); writer.writePropertyName("chords"); writer.writeStartObject(); - obj.chords.forEach((k, v) => { writer.writePropertyName(k); ChordSerializer.toJson(m); }); + obj.chords.forEach((v, k) => { writer.writePropertyName(k); ChordSerializer.toJson(v, writer); }); writer.writeEndObject(); writer.writePropertyName("capo"); writer.writeNumber(obj.capo); @@ -64,14 +65,19 @@ export class StaffSerializer { return true; case "bars": obj.bars = []; - for (const __li of value) - obj.addBar(BarSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Bar(); + BarSerializer.fromJson(i, reader) + obj.addBar(i); + } return true; case "chords": obj.chords = new Map(); - for (let __mk in value) - if (value.hasOwnProperty(__mk)) - obj.addChord(__mk, ChordSerializer.fromJson(value[__mk])); + while (reader.nextProperty()) { + const i = new Chord(); + ChordSerializer.fromJson(i, reader); + obj.addChord(reader.readPropertyName(), i); + } return true; case "capo": obj.capo = (reader.readNumber()!); diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index 634f374fa..0e2b7ad9f 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -11,6 +11,8 @@ import { StaffSerializer } from "@src/generated/model/StaffSerializer"; import { PlaybackInformationSerializer } from "@src/generated/model/PlaybackInformationSerializer"; import { Color } from "@src/model/Color"; import { InstrumentArticulationSerializer } from "@src/generated/model/InstrumentArticulationSerializer"; +import { Staff } from "@src/model/Staff"; +import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; export class TrackSerializer { public static fromJson(obj: Track, reader: IJsonReader): void { if (reader.currentValueType !== JsonValueType.Object) { @@ -57,11 +59,14 @@ export class TrackSerializer { return true; case "staves": obj.staves = []; - for (const __li of value) - obj.addStaff(StaffSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Staff(); + StaffSerializer.fromJson(i, reader) + obj.addStaff(i); + } return true; case "color": - obj.color = (Color.fromJson(value)!); + obj.color = (Color.fromJson(reader)!); return true; case "name": obj.name = (reader.readString()!); @@ -71,8 +76,11 @@ export class TrackSerializer { return true; case "percussionarticulations": obj.percussionArticulations = []; - for (const __li of value) - obj.percussionArticulations.push(InstrumentArticulationSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new InstrumentArticulation(); + InstrumentArticulationSerializer.fromJson(i, reader) + obj.percussionArticulations.push(i); + } return true; } if (["playbackinfo"].indexOf(property) >= 0) { diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index c4cd43df1..48114f8fd 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -8,6 +8,7 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { BeatSerializer } from "@src/generated/model/BeatSerializer"; +import { Beat } from "@src/model/Beat"; export class VoiceSerializer { public static fromJson(obj: Voice, reader: IJsonReader): void { if (reader.currentValueType !== JsonValueType.Object) { @@ -42,8 +43,11 @@ export class VoiceSerializer { return true; case "beats": obj.beats = []; - for (const __li of value) - obj.addBeat(BeatSerializer.fromJson(i, j)); + while (reader.nextArrayItem()) { + const i = new Beat(); + BeatSerializer.fromJson(i, reader) + obj.addBeat(i); + } return true; case "isempty": obj.isEmpty = (reader.readBoolean()!); diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts index c006beb57..9f5f5e79b 100644 --- a/src/io/IJsonReader.ts +++ b/src/io/IJsonReader.ts @@ -11,7 +11,11 @@ export interface IJsonReader { readonly currentValueType: JsonValueType; readPropertyName(): string; + readPropertyNameAsEnum(enumType: any): T; + readPropertyNameAsNumber(): number; + nextProperty(): boolean; + nextArrayItem(): boolean; readString(): string | null; readEnum(enumType: any): T | null; diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts index 936f229c4..cffca92af 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/IJsonWriter.ts @@ -5,7 +5,7 @@ export interface IJsonWriter { writeStartArray(): void; writeEndArray(): void; - writePropertyName(name: string): void; + writePropertyName(name: any): void; writeString(value: string | null): void; writeNumber(value: number | null): void; diff --git a/src/model/Color.ts b/src/model/Color.ts index 80ad2aa8f..11589c592 100644 --- a/src/model/Color.ts +++ b/src/model/Color.ts @@ -1,4 +1,6 @@ import { FormatError } from '@src/FormatError'; +import { IJsonReader, JsonValueType } from '@src/io/IJsonReader'; +import { IJsonWriter } from '@src/io/IJsonWriter'; import { ModelUtils } from './ModelUtils'; /** @@ -62,87 +64,85 @@ export class Color { return new Color((Math.random() * 255) | 0, (Math.random() * 255) | 0, (Math.random() * 255) | 0, opacity); } - public static fromJson(json: unknown): Color | null { - if (!json) { - return null; - } - if (json instanceof Color) { - return json; - } - - switch (typeof json) { - case 'number': - let c: Color = new Color(0, 0, 0, 0); - c.raw = json | 0; - c.updateRgba(); - return c; - - case 'string': - if (json.startsWith('#')) { - if (json.length === 4) { - // #RGB - return new Color( - parseInt(json.substring(1, 1), 16) * 17, - parseInt(json.substring(2, 1), 16) * 17, - parseInt(json.substring(3, 1), 16) * 17 - ); - } - - if (json.length === 5) { - // #RGBA - return new Color( - parseInt(json.substring(1, 1), 16) * 17, - parseInt(json.substring(2, 1), 16) * 17, - parseInt(json.substring(3, 1), 16) * 17, - parseInt(json.substring(4, 1), 16) * 17 - ); - } - - if (json.length === 7) { - // #RRGGBB - return new Color( - parseInt(json.substring(1, 2), 16), - parseInt(json.substring(3, 2), 16), - parseInt(json.substring(5, 2), 16) - ); - } - - if (json.length === 9) { - // #RRGGBBAA - return new Color( - parseInt(json.substring(1, 2), 16), - parseInt(json.substring(3, 2), 16), - parseInt(json.substring(5, 2), 16), - parseInt(json.substring(7, 2), 16) - ); - } - } else if (json.startsWith('rgba') || json.startsWith('rgb')) { - const start = json.indexOf('('); - const end = json.lastIndexOf(')'); - if (start === -1 || end === -1) { - throw new FormatError('No values specified for rgb/rgba function'); - } - - const numbers = json.substring(start + 1, end - start - 1).split(','); - if (numbers.length === 3) { - return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2])); - } - - if (numbers.length === 4) { - return new Color( - parseInt(numbers[0]), - parseInt(numbers[1]), - parseInt(numbers[2]), - parseFloat(numbers[3]) * 255 - ); + public static fromJson(reader: IJsonReader): Color | null { + switch (reader.currentValueType) { + case JsonValueType.Number: + { + const c = new Color(0, 0, 0, 0); + c.raw = reader.readNumber()!; + c.updateRgba(); + return c; + } + case JsonValueType.String: + { + const json = reader.readString()!; + if (json.startsWith('#')) { + if (json.length === 4) { + // #RGB + return new Color( + parseInt(json.substring(1, 1), 16) * 17, + parseInt(json.substring(2, 1), 16) * 17, + parseInt(json.substring(3, 1), 16) * 17 + ); + } + + if (json.length === 5) { + // #RGBA + return new Color( + parseInt(json.substring(1, 1), 16) * 17, + parseInt(json.substring(2, 1), 16) * 17, + parseInt(json.substring(3, 1), 16) * 17, + parseInt(json.substring(4, 1), 16) * 17 + ); + } + + if (json.length === 7) { + // #RRGGBB + return new Color( + parseInt(json.substring(1, 2), 16), + parseInt(json.substring(3, 2), 16), + parseInt(json.substring(5, 2), 16) + ); + } + + if (json.length === 9) { + // #RRGGBBAA + return new Color( + parseInt(json.substring(1, 2), 16), + parseInt(json.substring(3, 2), 16), + parseInt(json.substring(5, 2), 16), + parseInt(json.substring(7, 2), 16) + ); + } + } else if (json.startsWith('rgba') || json.startsWith('rgb')) { + const start = json.indexOf('('); + const end = json.lastIndexOf(')'); + if (start === -1 || end === -1) { + throw new FormatError('No values specified for rgb/rgba function'); + } + + const numbers = json.substring(start + 1, end - start - 1).split(','); + if (numbers.length === 3) { + return new Color(parseInt(numbers[0]), parseInt(numbers[1]), parseInt(numbers[2])); + } + + if (numbers.length === 4) { + return new Color( + parseInt(numbers[0]), + parseInt(numbers[1]), + parseInt(numbers[2]), + parseFloat(numbers[3]) * 255 + ); + } } + return null; } - break; } + throw new FormatError('Unsupported format for color'); } - public static toJson(obj: Color): unknown { - return obj.raw; + public static toJson(obj: Color, writer: IJsonWriter): void { + writer.writeNumber(obj.raw); } } diff --git a/src/model/Font.ts b/src/model/Font.ts index e2c2dd04c..0a0ef6b20 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -1,4 +1,6 @@ import { Environment } from '@src/Environment'; +import { IJsonReader, JsonValueType } from '@src/io/IJsonReader'; +import { IJsonWriter } from '@src/io/IJsonWriter'; /** * Lists all flags for font styles. @@ -79,101 +81,120 @@ export class Font { return this._css; } - public static fromJson(value: unknown): Font | null { - if (!value) { - return null; - } - - if (value instanceof Font) { - return value; - } - - if (typeof value === 'object' && (value as any).family) { - return new Font((value as any).family, (value as any).size, (value as any).style); - } + public static fromJson(reader: IJsonReader): Font | null { + switch (reader.currentValueType) { + case JsonValueType.Null: + return null; + case JsonValueType.Object: + { + let family = ''; + let size = 0; + let style = FontStyle.Plain; + while (reader.nextProperty()) { + switch (reader.readPropertyName().toLowerCase()) { + case 'family': + family = reader.readString()!; + break; + case 'size': + size = reader.readNumber()!; + break; + case 'style': + style = reader.readEnum(FontStyle)!; + break; + } + } + return new Font(family, size, style); + } + case JsonValueType.String: + if (!Environment.isRunningInWorker) { + const value = reader.readString(); + let el: HTMLElement = document.createElement('span'); + el.setAttribute('style', 'font: ' + value); + let style: CSSStyleDeclaration = el.style; + if (!style.fontFamily) { + style.fontFamily = 'sans-serif'; + } - if (typeof value === 'string' && !Environment.isRunningInWorker) { - let el: HTMLElement = document.createElement('span'); - el.setAttribute('style', 'font: ' + value); - let style: CSSStyleDeclaration = el.style; - if (!style.fontFamily) { - style.fontFamily = 'sans-serif'; - } + let family: string = style.fontFamily; + if ((family.startsWith("'") && family.endsWith("'")) || (family.startsWith('"') && family.endsWith('"'))) { + family = family.substr(1, family.length - 2); + } - let family: string = style.fontFamily; - if ((family.startsWith("'") && family.endsWith("'")) || (family.startsWith('"') && family.endsWith('"'))) { - family = family.substr(1, family.length - 2); - } + let fontSizeString: string = style.fontSize.toLowerCase(); + let fontSize: number = 0; + // as per https://websemantics.uk/articles/font-size-conversion/ + switch (fontSizeString) { + case 'xx-small': + fontSize = 7; + break; + case 'x-small': + fontSize = 10; + break; + case 'small': + case 'smaller': + fontSize = 13; + break; + case 'medium': + fontSize = 16; + break; + case 'large': + case 'larger': + fontSize = 18; + break; + case 'x-large': + fontSize = 24; + break; + case 'xx-large': + fontSize = 32; + break; + default: + try { + if (fontSizeString.endsWith('em')) { + fontSize = parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16; + } else if (fontSizeString.endsWith('pt')) { + fontSize = (parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16.0) / 12.0; + } else if (fontSizeString.endsWith('px')) { + fontSize = parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)); + } else { + fontSize = 12; + } + } catch (e) { + fontSize = 12; + } + break; + } - let fontSizeString: string = style.fontSize.toLowerCase(); - let fontSize: number = 0; - // as per https://websemantics.uk/articles/font-size-conversion/ - switch (fontSizeString) { - case 'xx-small': - fontSize = 7; - break; - case 'x-small': - fontSize = 10; - break; - case 'small': - case 'smaller': - fontSize = 13; - break; - case 'medium': - fontSize = 16; - break; - case 'large': - case 'larger': - fontSize = 18; - break; - case 'x-large': - fontSize = 24; - break; - case 'xx-large': - fontSize = 32; - break; - default: - try { - if (fontSizeString.endsWith('em')) { - fontSize = parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16; - } else if (fontSizeString.endsWith('pt')) { - fontSize = (parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)) * 16.0) / 12.0; - } else if (fontSizeString.endsWith('px')) { - fontSize = parseFloat(fontSizeString.substr(0, fontSizeString.length - 2)); - } else { - fontSize = 12; - } - } catch (e) { - fontSize = 12; + let fontStyle: FontStyle = FontStyle.Plain; + if (style.fontStyle === 'italic') { + fontStyle |= FontStyle.Italic; + } + let fontWeightString: string = style.fontWeight.toLowerCase(); + switch (fontWeightString) { + case 'normal': + case 'lighter': + break; + default: + fontStyle |= FontStyle.Bold; + break; } - break; - } - let fontStyle: FontStyle = FontStyle.Plain; - if (style.fontStyle === 'italic') { - fontStyle |= FontStyle.Italic; - } - let fontWeightString: string = style.fontWeight.toLowerCase(); - switch (fontWeightString) { - case 'normal': - case 'lighter': - break; - default: - fontStyle |= FontStyle.Bold; - break; - } + return new Font(family, fontSize, fontStyle); + } - return new Font(family, fontSize, fontStyle); + return null; + default: + return null; } - - return null; } - - public static toJson(font: Font): unknown { - return { - family: font.family, - size: font.size, - style: font.style - }; + + public static toJson(font: Font, writer: IJsonWriter): void { + writer.writeStartObject(); + writer.writePropertyName('family'); + writer.writeString(font.family); + writer.writePropertyName('size'); + writer.writeNumber(font.size); + writer.writePropertyName('style'); + writer.writeEnum(font.style); + writer.writeEndObject(); } } diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index e20ceb575..73823552e 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -7,6 +7,7 @@ import { Score } from '@src/model/Score'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; import { ScoreSerializer } from '@src/generated/model/ScoreSerializer'; +import { IJsonReader } from '@src/io/IJsonReader'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further @@ -36,7 +37,8 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - return ScoreSerializer.toJson(score); + // TODO: create writer + return ScoreSerializer.toJson(score, null!); } /** @@ -56,7 +58,9 @@ export class JsonConverter { * @returns The converted score object. */ public static jsObjectToScore(jsObject: any, settings?: Settings): Score { - let score: Score = ScoreSerializer.fromJson(jsObject); + // TODO: create reader + let score: Score = new Score(); + ScoreSerializer.fromJson(score, jsObject as IJsonReader); score.finish(settings ?? new Settings()); return score; } diff --git a/src/platform/javascript/AlphaTabWebWorker.ts b/src/platform/javascript/AlphaTabWebWorker.ts index b4a27381f..ecc4e1ad1 100644 --- a/src/platform/javascript/AlphaTabWebWorker.ts +++ b/src/platform/javascript/AlphaTabWebWorker.ts @@ -7,6 +7,7 @@ import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { Environment } from '@src/Environment'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; +import { IJsonReader } from '@src/io/IJsonReader'; /** * @target web @@ -30,7 +31,8 @@ export class AlphaTabWebWorker { switch (cmd) { case 'alphaTab.initialize': let settings: Settings = new Settings(); - SettingsSerializer.fillFromJson(settings, data.settings); + // TODO: create json reader + SettingsSerializer.fromJson(settings, data.settings as IJsonReader); Logger.logLevel = settings.core.logLevel; this._renderer = new ScoreRenderer(settings); this._renderer.partialRenderFinished.on(result => { @@ -91,7 +93,7 @@ export class AlphaTabWebWorker { } private updateSettings(json: unknown): void { - SettingsSerializer.fillFromJson(this._renderer.settings, json); + SettingsSerializer.fromJson(this._renderer.settings, json as IJsonReader); } private renderMultiple(score: Score, trackIndexes: number[]): void { diff --git a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts index 433ec8da9..54e8c78b9 100644 --- a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts +++ b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts @@ -60,7 +60,8 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { } private serializeSettingsForWorker(settings: Settings): unknown { - let json: any = SettingsSerializer.toJson(settings); + // TODO: create Web variant of JSON writer + let json: any = SettingsSerializer.toJson(settings, null!); // cut out player settings, they are only needed on UI thread side json.player = null; return json; diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index 5db944f80..b6451e571 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -24,6 +24,7 @@ import { AlphaTabWorkerScoreRenderer } from '@src/platform/javascript/AlphaTabWo import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; import { Cursors } from '@src/platform/Cursors'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; +import { IJsonReader } from '@src/io/IJsonReader'; /** * @target web @@ -123,7 +124,8 @@ export class BrowserUiFacade implements IUiFacade { settings = raw; } else { settings = new Settings(); - SettingsSerializer.fillFromJson(settings, raw); + // TODO: implement web variant of JSON reader + SettingsSerializer.fromJson(settings, raw as IJsonReader); } let dataAttributes: Map = this.getDataAttributes(); From f9928a273136176bfa2a212c507e535ca609cce5 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sat, 19 Dec 2020 23:35:41 +0100 Subject: [PATCH 10/19] Smaller footprint --- src.compiler/typescript/SerializerEmitter.ts | 108 +++---- src/generated/CoreSettingsSerializer.ts | 78 ++--- src/generated/DisplaySettingsSerializer.ts | 80 ++--- src/generated/ImporterSettingsSerializer.ts | 30 +- src/generated/NotationSettingsSerializer.ts | 90 +++--- src/generated/PlayerSettingsSerializer.ts | 90 +++--- src/generated/RenderingResourcesSerializer.ts | 120 ++++---- src/generated/SettingsSerializer.ts | 58 ++-- .../SlidePlaybackSettingsSerializer.ts | 36 +-- .../VibratoPlaybackSettingsSerializer.ts | 66 ++-- src/generated/model/AutomationSerializer.ts | 48 +-- src/generated/model/BarSerializer.ts | 60 ++-- src/generated/model/BeatSerializer.ts | 282 +++++++++--------- src/generated/model/BendPointSerializer.ts | 30 +- src/generated/model/ChordSerializer.ts | 60 ++-- src/generated/model/FermataSerializer.ts | 30 +- .../model/InstrumentArticulationSerializer.ts | 60 ++-- src/generated/model/MasterBarSerializer.ts | 130 ++++---- src/generated/model/NoteSerializer.ts | 282 +++++++++--------- .../model/PlaybackInformationSerializer.ts | 66 ++-- .../model/RenderStylesheetSerializer.ts | 24 +- src/generated/model/ScoreSerializer.ts | 120 ++++---- src/generated/model/SectionSerializer.ts | 30 +- src/generated/model/StaffSerializer.ts | 104 +++---- src/generated/model/TrackSerializer.ts | 72 ++--- src/generated/model/VoiceSerializer.ts | 42 +-- src/io/IJsonReader.ts | 42 +-- src/io/IJsonWriter.ts | 42 +-- src/model/Color.ts | 6 +- src/model/Font.ts | 28 +- 30 files changed, 1157 insertions(+), 1157 deletions(-) diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index d94afb4b0..60e20c166 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -77,7 +77,7 @@ function generateFromJsonBody() { return ts.factory.createBlock(addNewLines([ ts.factory.createIfStatement( ts.factory.createBinaryExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'currentValueType'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'currentValueType'), ts.SyntaxKind.ExclamationEqualsEqualsToken, ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Object'), ), @@ -88,7 +88,7 @@ function generateFromJsonBody() { ts.factory.createWhileStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextProperty'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextProp'), undefined, [] ), @@ -102,7 +102,7 @@ function generateFromJsonBody() { ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyName'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'prop'), undefined, [] ), @@ -111,7 +111,7 @@ function generateFromJsonBody() { undefined, [] ), - ts.factory.createIdentifier('reader'), + ts.factory.createIdentifier('r'), ] ) ) @@ -150,7 +150,7 @@ function createFromJsonMethod(input: ts.ClassDeclaration, undefined, undefined, undefined, - 'reader', + 'r', undefined, ts.factory.createTypeReferenceNode('IJsonReader') ) @@ -171,28 +171,28 @@ function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeCheck const arrayItemType = unwrapArrayItemType(type, typeChecker); if (hasFlag(type, ts.TypeFlags.Number)) { - return "writeNumber"; + return "number"; } if (hasFlag(type, ts.TypeFlags.String)) { - return "writeString"; + return "string"; } if (hasFlag(type, ts.TypeFlags.Boolean)) { - return "writeBoolean"; + return "boolean"; } if (isEnumType(type)) { - return 'writeEnum'; + return 'enum'; } if (arrayItemType) { if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { - return "writeNumberArray"; + return "numberArray"; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { - return "writeStringArray"; + return "stringArray"; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { - return "writeBooleanArray"; + return "booleanArray"; } } else if (type.symbol) { switch (type.symbol.name) { @@ -204,7 +204,7 @@ function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeCheck case 'Int32Array': case 'Float32Array': case 'Float64Array': - return 'write' + type.symbol.name; + return type.symbol.name.substring(0, 1).toLowerCase() + type.symbol.name.substring(1); } } @@ -225,7 +225,7 @@ function generateToJsonBody( ), ts.factory.createBlock([ ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeNull'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'null'), undefined, [] )), ts.factory.createReturnStatement() @@ -233,7 +233,7 @@ function generateToJsonBody( )) statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartObject'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startObject'), undefined, [] ))); @@ -242,7 +242,7 @@ function generateToJsonBody( const jsonName = prop.jsonNames.filter(n => n !== '')[0]; statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writePropertyName'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ ts.factory.createStringLiteral(jsonName) @@ -260,7 +260,7 @@ function generateToJsonBody( if (writeValueMethodName) { statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), writeValueMethodName), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), writeValueMethodName), undefined, [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), @@ -275,7 +275,7 @@ function generateToJsonBody( importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartArray'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startArray'), undefined, [] ))); @@ -294,7 +294,7 @@ function generateToJsonBody( undefined, [ ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('writer') + ts.factory.createIdentifier('w') ] ) ) @@ -302,7 +302,7 @@ function generateToJsonBody( )); statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndArray'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endArray'), undefined, [] ))); @@ -319,7 +319,7 @@ function generateToJsonBody( itemSerializer = ''; writeValue = ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('writer'), + ts.factory.createIdentifier('w'), getWriteMethodNameForPrimitive(mapType.typeArguments![1], typeChecker)! ), undefined, @@ -333,13 +333,13 @@ function generateToJsonBody( undefined, [ ts.factory.createIdentifier('v'), - ts.factory.createIdentifier('writer') + ts.factory.createIdentifier('w') ] ); } statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeStartObject'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startObject'), undefined, [] ))); @@ -360,7 +360,7 @@ function generateToJsonBody( ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock([ ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writePropertyName'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ts.factory.createIdentifier('k')] )), @@ -372,7 +372,7 @@ function generateToJsonBody( ); statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndObject'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endObject'), undefined, [] ))); @@ -387,7 +387,7 @@ function generateToJsonBody( [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('writer') + ts.factory.createIdentifier('w') ] ) ) @@ -406,7 +406,7 @@ function generateToJsonBody( [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('writer'), + ts.factory.createIdentifier('w'), ] )); @@ -417,7 +417,7 @@ function generateToJsonBody( writeValue ]), ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeNull'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'null'), undefined, [] )) @@ -429,7 +429,7 @@ function generateToJsonBody( } statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('writer'), 'writeEndObject'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endObject'), undefined, [] ))); @@ -471,7 +471,7 @@ function createToJsonMethod(program: ts.Program, undefined, undefined, undefined, - 'writer', + 'w', undefined, ts.factory.createTypeReferenceNode('IJsonWriter') ) @@ -493,24 +493,24 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke const arrayItemType = unwrapArrayItemType(type, typeChecker); if (hasFlag(type, ts.TypeFlags.Number)) { - return "readNumber"; + return "number"; } if (hasFlag(type, ts.TypeFlags.String)) { - return "readString"; + return "string"; } if (hasFlag(type, ts.TypeFlags.Boolean)) { - return "readBoolean"; + return "boolean"; } if (arrayItemType) { if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { - return "readNumberArray"; + return "numberArray"; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { - return "readStringArray"; + return "stringArray"; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { - return "readBooleanArray"; + return "booleanArray"; } } else if (type.symbol) { switch (type.symbol.name) { @@ -522,7 +522,7 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke case 'Int32Array': case 'Float32Array': case 'Float64Array': - return 'read' + type.symbol.name; + return type.symbol.name.substr(0, 1).toLowerCase() + type.symbol.name.substr(1); } } @@ -533,8 +533,8 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke function createEnumMapping(type: ts.Type): ts.Expression { return ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('reader'), - 'readEnum' + ts.factory.createIdentifier('r'), + 'enum' ), [ts.factory.createTypeReferenceNode(type.symbol.name)], [ @@ -570,7 +570,7 @@ function generateSetPropertyBody(program: ts.Program, if (primitiveRead) { const read = ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('reader'), + ts.factory.createIdentifier('r'), primitiveRead ), undefined, @@ -616,7 +616,7 @@ function generateSetPropertyBody(program: ts.Program, assignField(ts.factory.createArrayLiteralExpression(undefined)), ts.factory.createWhileStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextArrayItem'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextItem'), undefined, [] ), @@ -639,7 +639,7 @@ function generateSetPropertyBody(program: ts.Program, undefined, [ ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('reader') + ts.factory.createIdentifier('r') ] ), ts.factory.createExpressionStatement( @@ -690,19 +690,19 @@ function generateSetPropertyBody(program: ts.Program, if (isEnumType(mapType.typeArguments![0])) { importer(mapType.typeArguments![0].symbol!.name, findModule(mapType.typeArguments![0], program.getCompilerOptions())); mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyNameAsEnum'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'enumProp'), [ts.factory.createTypeReferenceNode(mapType.typeArguments![0].symbol!.name)], [ts.factory.createIdentifier(mapType.typeArguments![0].symbol!.name)] ); } else if (isNumberType(mapType.typeArguments![0])) { mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyNameAsNumber'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'numberProp'), undefined, [] ); } else { mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'readPropertyName'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'prop'), undefined, [] ); @@ -714,7 +714,7 @@ function generateSetPropertyBody(program: ts.Program, if (primitiveReadForValue) { mapValue = ts.factory.createNonNullExpression(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('reader'), + ts.factory.createIdentifier('r'), primitiveReadForValue ), undefined, @@ -739,7 +739,7 @@ function generateSetPropertyBody(program: ts.Program, caseStatements.push(ts.factory.createWhileStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'nextProperty'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextProp'), undefined, [] ), @@ -762,7 +762,7 @@ function generateSetPropertyBody(program: ts.Program, undefined, [ ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('reader'), + ts.factory.createIdentifier('r'), ] ) ), @@ -799,7 +799,7 @@ function generateSetPropertyBody(program: ts.Program, ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), [], [ - ts.factory.createIdentifier('reader') + ts.factory.createIdentifier('r') ] ), ts.factory @@ -842,7 +842,7 @@ function generateSetPropertyBody(program: ts.Program, [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('reader') + ts.factory.createIdentifier('r') ] ) ), @@ -851,7 +851,7 @@ function generateSetPropertyBody(program: ts.Program, : [ ts.factory.createIfStatement( ts.factory.createBinaryExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('reader'), 'currentValueType'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'currentValueType'), ts.SyntaxKind.ExclamationEqualsEqualsToken, ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Null'), ), @@ -868,7 +868,7 @@ function generateSetPropertyBody(program: ts.Program, [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('reader') + ts.factory.createIdentifier('r') ] ) ) @@ -929,7 +929,7 @@ function generateSetPropertyBody(program: ts.Program, [], [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('c'), 'length')] ), - ts.factory.createIdentifier('reader') + ts.factory.createIdentifier('r') ] ), ts.factory.createBlock([ @@ -1005,7 +1005,7 @@ function createSetPropertyMethod( undefined, undefined, undefined, - 'reader', + 'r', undefined, ts.factory.createTypeReferenceNode('IJsonReader') ) diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index 727869f7f..f1f94e71a 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -9,73 +9,73 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { LogLevel } from "@src/LogLevel"; export class CoreSettingsSerializer { - public static fromJson(obj: CoreSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: CoreSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: CoreSettings | null, writer: IJsonWriter): void { + public static toJson(obj: CoreSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("scriptFile"); - writer.writeString(obj.scriptFile); - writer.writePropertyName("fontDirectory"); - writer.writeString(obj.fontDirectory); - writer.writePropertyName("file"); - writer.writeString(obj.file); - writer.writePropertyName("tex"); - writer.writeBoolean(obj.tex); - writer.writePropertyName("visibilityCheckInterval"); - writer.writeNumber(obj.visibilityCheckInterval); - writer.writePropertyName("enableLazyLoading"); - writer.writeBoolean(obj.enableLazyLoading); - writer.writePropertyName("engine"); - writer.writeString(obj.engine); - writer.writePropertyName("logLevel"); - writer.writeEnum(obj.logLevel); - writer.writePropertyName("useWorkers"); - writer.writeBoolean(obj.useWorkers); - writer.writePropertyName("includeNoteBounds"); - writer.writeBoolean(obj.includeNoteBounds); - writer.writeEndObject(); + w.startObject(); + w.prop("scriptFile"); + w.string(obj.scriptFile); + w.prop("fontDirectory"); + w.string(obj.fontDirectory); + w.prop("file"); + w.string(obj.file); + w.prop("tex"); + w.boolean(obj.tex); + w.prop("visibilityCheckInterval"); + w.number(obj.visibilityCheckInterval); + w.prop("enableLazyLoading"); + w.boolean(obj.enableLazyLoading); + w.prop("engine"); + w.string(obj.engine); + w.prop("logLevel"); + w.enum(obj.logLevel); + w.prop("useWorkers"); + w.boolean(obj.useWorkers); + w.prop("includeNoteBounds"); + w.boolean(obj.includeNoteBounds); + w.endObject(); } - public static setProperty(obj: CoreSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: CoreSettings, property: string, r: IJsonReader): boolean { switch (property) { case "scriptfile": - obj.scriptFile = reader.readString(); + obj.scriptFile = r.string(); return true; case "fontdirectory": - obj.fontDirectory = reader.readString(); + obj.fontDirectory = r.string(); return true; case "file": - obj.file = reader.readString(); + obj.file = r.string(); return true; case "tex": - obj.tex = (reader.readBoolean()!); + obj.tex = (r.boolean()!); return true; case "visibilitycheckinterval": - obj.visibilityCheckInterval = (reader.readNumber()!); + obj.visibilityCheckInterval = (r.number()!); return true; case "enablelazyloading": - obj.enableLazyLoading = (reader.readBoolean()!); + obj.enableLazyLoading = (r.boolean()!); return true; case "engine": - obj.engine = (reader.readString()!); + obj.engine = (r.string()!); return true; case "loglevel": - obj.logLevel = (reader.readEnum(LogLevel)!); + obj.logLevel = (r.enum(LogLevel)!); return true; case "useworkers": - obj.useWorkers = (reader.readBoolean()!); + obj.useWorkers = (r.boolean()!); return true; case "includenotebounds": - obj.includeNoteBounds = (reader.readBoolean()!); + obj.includeNoteBounds = (r.boolean()!); return true; } return false; diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts index ed818de23..ab9beb422 100644 --- a/src/generated/DisplaySettingsSerializer.ts +++ b/src/generated/DisplaySettingsSerializer.ts @@ -11,80 +11,80 @@ import { RenderingResourcesSerializer } from "@src/generated/RenderingResourcesS import { LayoutMode } from "@src/DisplaySettings"; import { StaveProfile } from "@src/DisplaySettings"; export class DisplaySettingsSerializer { - public static fromJson(obj: DisplaySettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: DisplaySettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: DisplaySettings | null, writer: IJsonWriter): void { + public static toJson(obj: DisplaySettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("scale"); - writer.writeNumber(obj.scale); - writer.writePropertyName("stretchForce"); - writer.writeNumber(obj.stretchForce); - writer.writePropertyName("layoutMode"); - writer.writeEnum(obj.layoutMode); - writer.writePropertyName("staveProfile"); - writer.writeEnum(obj.staveProfile); - writer.writePropertyName("barsPerRow"); - writer.writeNumber(obj.barsPerRow); - writer.writePropertyName("startBar"); - writer.writeNumber(obj.startBar); - writer.writePropertyName("barCount"); - writer.writeNumber(obj.barCount); - writer.writePropertyName("barCountPerPartial"); - writer.writeNumber(obj.barCountPerPartial); - writer.writePropertyName("resources"); - RenderingResourcesSerializer.toJson(obj.resources, writer); - writer.writePropertyName("padding"); - writer.writeFloat32Array(obj.padding); - writer.writeEndObject(); + w.startObject(); + w.prop("scale"); + w.number(obj.scale); + w.prop("stretchForce"); + w.number(obj.stretchForce); + w.prop("layoutMode"); + w.enum(obj.layoutMode); + w.prop("staveProfile"); + w.enum(obj.staveProfile); + w.prop("barsPerRow"); + w.number(obj.barsPerRow); + w.prop("startBar"); + w.number(obj.startBar); + w.prop("barCount"); + w.number(obj.barCount); + w.prop("barCountPerPartial"); + w.number(obj.barCountPerPartial); + w.prop("resources"); + RenderingResourcesSerializer.toJson(obj.resources, w); + w.prop("padding"); + w.float32Array(obj.padding); + w.endObject(); } - public static setProperty(obj: DisplaySettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: DisplaySettings, property: string, r: IJsonReader): boolean { switch (property) { case "scale": - obj.scale = (reader.readNumber()!); + obj.scale = (r.number()!); return true; case "stretchforce": - obj.stretchForce = (reader.readNumber()!); + obj.stretchForce = (r.number()!); return true; case "layoutmode": - obj.layoutMode = (reader.readEnum(LayoutMode)!); + obj.layoutMode = (r.enum(LayoutMode)!); return true; case "staveprofile": - obj.staveProfile = (reader.readEnum(StaveProfile)!); + obj.staveProfile = (r.enum(StaveProfile)!); return true; case "barsperrow": - obj.barsPerRow = (reader.readNumber()!); + obj.barsPerRow = (r.number()!); return true; case "startbar": - obj.startBar = (reader.readNumber()!); + obj.startBar = (r.number()!); return true; case "barcount": - obj.barCount = (reader.readNumber()!); + obj.barCount = (r.number()!); return true; case "barcountperpartial": - obj.barCountPerPartial = (reader.readNumber()!); + obj.barCountPerPartial = (r.number()!); return true; case "padding": - obj.padding = reader.readFloat32Array(); + obj.padding = r.float32Array(); return true; } if (["resources"].indexOf(property) >= 0) { - RenderingResourcesSerializer.fromJson(obj.resources, reader); + RenderingResourcesSerializer.fromJson(obj.resources, r); return true; } else { for (const c of ["resources"]) { if (property.indexOf(c) === 0) { - if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), reader)) { + if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), r)) { return true; } } diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts index bf1509c1e..b8a95c259 100644 --- a/src/generated/ImporterSettingsSerializer.ts +++ b/src/generated/ImporterSettingsSerializer.ts @@ -8,33 +8,33 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class ImporterSettingsSerializer { - public static fromJson(obj: ImporterSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: ImporterSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: ImporterSettings | null, writer: IJsonWriter): void { + public static toJson(obj: ImporterSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("encoding"); - writer.writeString(obj.encoding); - writer.writePropertyName("mergePartGroupsInMusicXml"); - writer.writeBoolean(obj.mergePartGroupsInMusicXml); - writer.writeEndObject(); + w.startObject(); + w.prop("encoding"); + w.string(obj.encoding); + w.prop("mergePartGroupsInMusicXml"); + w.boolean(obj.mergePartGroupsInMusicXml); + w.endObject(); } - public static setProperty(obj: ImporterSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: ImporterSettings, property: string, r: IJsonReader): boolean { switch (property) { case "encoding": - obj.encoding = (reader.readString()!); + obj.encoding = (r.string()!); return true; case "mergepartgroupsinmusicxml": - obj.mergePartGroupsInMusicXml = (reader.readBoolean()!); + obj.mergePartGroupsInMusicXml = (r.boolean()!); return true; } return false; diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 4bf715adc..2069d004f 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -12,83 +12,83 @@ import { FingeringMode } from "@src/NotationSettings"; import { NotationElement } from "@src/NotationSettings"; import { TabRhythmMode } from "@src/NotationSettings"; export class NotationSettingsSerializer { - public static fromJson(obj: NotationSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: NotationSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: NotationSettings | null, writer: IJsonWriter): void { + public static toJson(obj: NotationSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("notationMode"); - writer.writeEnum(obj.notationMode); - writer.writePropertyName("fingeringMode"); - writer.writeEnum(obj.fingeringMode); - writer.writePropertyName("elements"); - writer.writeStartObject(); - obj.elements.forEach((v, k) => { writer.writePropertyName(k); writer.writeBoolean(v); }); - writer.writeEndObject(); - writer.writePropertyName("rhythmMode"); - writer.writeEnum(obj.rhythmMode); - writer.writePropertyName("rhythmHeight"); - writer.writeNumber(obj.rhythmHeight); - writer.writePropertyName("transpositionPitches"); - writer.writeNumberArray(obj.transpositionPitches); - writer.writePropertyName("displayTranspositionPitches"); - writer.writeNumberArray(obj.displayTranspositionPitches); - writer.writePropertyName("smallGraceTabNotes"); - writer.writeBoolean(obj.smallGraceTabNotes); - writer.writePropertyName("extendBendArrowsOnTiedNotes"); - writer.writeBoolean(obj.extendBendArrowsOnTiedNotes); - writer.writePropertyName("extendLineEffectsToBeatEnd"); - writer.writeBoolean(obj.extendLineEffectsToBeatEnd); - writer.writePropertyName("slurHeight"); - writer.writeNumber(obj.slurHeight); - writer.writeEndObject(); + w.startObject(); + w.prop("notationMode"); + w.enum(obj.notationMode); + w.prop("fingeringMode"); + w.enum(obj.fingeringMode); + w.prop("elements"); + w.startObject(); + obj.elements.forEach((v, k) => { w.prop(k); w.boolean(v); }); + w.endObject(); + w.prop("rhythmMode"); + w.enum(obj.rhythmMode); + w.prop("rhythmHeight"); + w.number(obj.rhythmHeight); + w.prop("transpositionPitches"); + w.numberArray(obj.transpositionPitches); + w.prop("displayTranspositionPitches"); + w.numberArray(obj.displayTranspositionPitches); + w.prop("smallGraceTabNotes"); + w.boolean(obj.smallGraceTabNotes); + w.prop("extendBendArrowsOnTiedNotes"); + w.boolean(obj.extendBendArrowsOnTiedNotes); + w.prop("extendLineEffectsToBeatEnd"); + w.boolean(obj.extendLineEffectsToBeatEnd); + w.prop("slurHeight"); + w.number(obj.slurHeight); + w.endObject(); } - public static setProperty(obj: NotationSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: NotationSettings, property: string, r: IJsonReader): boolean { switch (property) { case "notationmode": - obj.notationMode = (reader.readEnum(NotationMode)!); + obj.notationMode = (r.enum(NotationMode)!); return true; case "fingeringmode": - obj.fingeringMode = (reader.readEnum(FingeringMode)!); + obj.fingeringMode = (r.enum(FingeringMode)!); return true; case "elements": obj.elements = new Map(); - while (reader.nextProperty()) { - obj.elements.set(reader.readPropertyNameAsEnum(NotationElement), (reader.readBoolean()!)); + while (r.nextProp()) { + obj.elements.set(r.enumProp(NotationElement), (r.boolean()!)); } return true; case "rhythmmode": - obj.rhythmMode = (reader.readEnum(TabRhythmMode)!); + obj.rhythmMode = (r.enum(TabRhythmMode)!); return true; case "rhythmheight": - obj.rhythmHeight = (reader.readNumber()!); + obj.rhythmHeight = (r.number()!); return true; case "transpositionpitches": - obj.transpositionPitches = (reader.readNumberArray()!); + obj.transpositionPitches = (r.numberArray()!); return true; case "displaytranspositionpitches": - obj.displayTranspositionPitches = (reader.readNumberArray()!); + obj.displayTranspositionPitches = (r.numberArray()!); return true; case "smallgracetabnotes": - obj.smallGraceTabNotes = (reader.readBoolean()!); + obj.smallGraceTabNotes = (r.boolean()!); return true; case "extendbendarrowsontiednotes": - obj.extendBendArrowsOnTiedNotes = (reader.readBoolean()!); + obj.extendBendArrowsOnTiedNotes = (r.boolean()!); return true; case "extendlineeffectstobeatend": - obj.extendLineEffectsToBeatEnd = (reader.readBoolean()!); + obj.extendLineEffectsToBeatEnd = (r.boolean()!); return true; case "slurheight": - obj.slurHeight = (reader.readNumber()!); + obj.slurHeight = (r.number()!); return true; } return false; diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index 06e8bde78..d6e48e547 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -9,83 +9,83 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { - public static fromJson(obj: PlayerSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: PlayerSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: PlayerSettings | null, writer: IJsonWriter): void { + public static toJson(obj: PlayerSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("soundFont"); - writer.writeString(obj.soundFont); - writer.writePropertyName("scrollElement"); - writer.writeString(obj.scrollElement); - writer.writePropertyName("enablePlayer"); - writer.writeBoolean(obj.enablePlayer); - writer.writePropertyName("enableCursor"); - writer.writeBoolean(obj.enableCursor); - writer.writePropertyName("enableUserInteraction"); - writer.writeBoolean(obj.enableUserInteraction); - writer.writePropertyName("scrollOffsetX"); - writer.writeNumber(obj.scrollOffsetX); - writer.writePropertyName("scrollOffsetY"); - writer.writeNumber(obj.scrollOffsetY); - writer.writePropertyName("scrollMode"); - writer.writeEnum(obj.scrollMode); - writer.writePropertyName("scrollSpeed"); - writer.writeNumber(obj.scrollSpeed); - writer.writePropertyName("songBookBendDuration"); - writer.writeNumber(obj.songBookBendDuration); - writer.writePropertyName("songBookDipDuration"); - writer.writeNumber(obj.songBookDipDuration); - writer.writePropertyName("playTripletFeel"); - writer.writeBoolean(obj.playTripletFeel); - writer.writeEndObject(); + w.startObject(); + w.prop("soundFont"); + w.string(obj.soundFont); + w.prop("scrollElement"); + w.string(obj.scrollElement); + w.prop("enablePlayer"); + w.boolean(obj.enablePlayer); + w.prop("enableCursor"); + w.boolean(obj.enableCursor); + w.prop("enableUserInteraction"); + w.boolean(obj.enableUserInteraction); + w.prop("scrollOffsetX"); + w.number(obj.scrollOffsetX); + w.prop("scrollOffsetY"); + w.number(obj.scrollOffsetY); + w.prop("scrollMode"); + w.enum(obj.scrollMode); + w.prop("scrollSpeed"); + w.number(obj.scrollSpeed); + w.prop("songBookBendDuration"); + w.number(obj.songBookBendDuration); + w.prop("songBookDipDuration"); + w.number(obj.songBookDipDuration); + w.prop("playTripletFeel"); + w.boolean(obj.playTripletFeel); + w.endObject(); } - public static setProperty(obj: PlayerSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: PlayerSettings, property: string, r: IJsonReader): boolean { switch (property) { case "soundfont": - obj.soundFont = reader.readString(); + obj.soundFont = r.string(); return true; case "scrollelement": - obj.scrollElement = (reader.readString()!); + obj.scrollElement = (r.string()!); return true; case "enableplayer": - obj.enablePlayer = (reader.readBoolean()!); + obj.enablePlayer = (r.boolean()!); return true; case "enablecursor": - obj.enableCursor = (reader.readBoolean()!); + obj.enableCursor = (r.boolean()!); return true; case "enableuserinteraction": - obj.enableUserInteraction = (reader.readBoolean()!); + obj.enableUserInteraction = (r.boolean()!); return true; case "scrolloffsetx": - obj.scrollOffsetX = (reader.readNumber()!); + obj.scrollOffsetX = (r.number()!); return true; case "scrolloffsety": - obj.scrollOffsetY = (reader.readNumber()!); + obj.scrollOffsetY = (r.number()!); return true; case "scrollmode": - obj.scrollMode = (reader.readEnum(ScrollMode)!); + obj.scrollMode = (r.enum(ScrollMode)!); return true; case "scrollspeed": - obj.scrollSpeed = (reader.readNumber()!); + obj.scrollSpeed = (r.number()!); return true; case "songbookbendduration": - obj.songBookBendDuration = (reader.readNumber()!); + obj.songBookBendDuration = (r.number()!); return true; case "songbookdipduration": - obj.songBookDipDuration = (reader.readNumber()!); + obj.songBookDipDuration = (r.number()!); return true; case "playtripletfeel": - obj.playTripletFeel = (reader.readBoolean()!); + obj.playTripletFeel = (r.boolean()!); return true; } return false; diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index 2457546fe..634997f8c 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -10,108 +10,108 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { Font } from "@src/model/Font"; import { Color } from "@src/model/Color"; export class RenderingResourcesSerializer { - public static fromJson(obj: RenderingResources, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: RenderingResources, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: RenderingResources | null, writer: IJsonWriter): void { + public static toJson(obj: RenderingResources | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("copyrightFont"); - Font.toJson(obj.copyrightFont, writer); - writer.writePropertyName("titleFont"); - Font.toJson(obj.titleFont, writer); - writer.writePropertyName("subTitleFont"); - Font.toJson(obj.subTitleFont, writer); - writer.writePropertyName("wordsFont"); - Font.toJson(obj.wordsFont, writer); - writer.writePropertyName("effectFont"); - Font.toJson(obj.effectFont, writer); - writer.writePropertyName("fretboardNumberFont"); - Font.toJson(obj.fretboardNumberFont, writer); - writer.writePropertyName("tablatureFont"); - Font.toJson(obj.tablatureFont, writer); - writer.writePropertyName("graceFont"); - Font.toJson(obj.graceFont, writer); - writer.writePropertyName("staffLineColor"); - Color.toJson(obj.staffLineColor, writer); - writer.writePropertyName("barSeparatorColor"); - Color.toJson(obj.barSeparatorColor, writer); - writer.writePropertyName("barNumberFont"); - Font.toJson(obj.barNumberFont, writer); - writer.writePropertyName("barNumberColor"); - Color.toJson(obj.barNumberColor, writer); - writer.writePropertyName("fingeringFont"); - Font.toJson(obj.fingeringFont, writer); - writer.writePropertyName("markerFont"); - Font.toJson(obj.markerFont, writer); - writer.writePropertyName("mainGlyphColor"); - Color.toJson(obj.mainGlyphColor, writer); - writer.writePropertyName("secondaryGlyphColor"); - Color.toJson(obj.secondaryGlyphColor, writer); - writer.writePropertyName("scoreInfoColor"); - Color.toJson(obj.scoreInfoColor, writer); - writer.writeEndObject(); + w.startObject(); + w.prop("copyrightFont"); + Font.toJson(obj.copyrightFont, w); + w.prop("titleFont"); + Font.toJson(obj.titleFont, w); + w.prop("subTitleFont"); + Font.toJson(obj.subTitleFont, w); + w.prop("wordsFont"); + Font.toJson(obj.wordsFont, w); + w.prop("effectFont"); + Font.toJson(obj.effectFont, w); + w.prop("fretboardNumberFont"); + Font.toJson(obj.fretboardNumberFont, w); + w.prop("tablatureFont"); + Font.toJson(obj.tablatureFont, w); + w.prop("graceFont"); + Font.toJson(obj.graceFont, w); + w.prop("staffLineColor"); + Color.toJson(obj.staffLineColor, w); + w.prop("barSeparatorColor"); + Color.toJson(obj.barSeparatorColor, w); + w.prop("barNumberFont"); + Font.toJson(obj.barNumberFont, w); + w.prop("barNumberColor"); + Color.toJson(obj.barNumberColor, w); + w.prop("fingeringFont"); + Font.toJson(obj.fingeringFont, w); + w.prop("markerFont"); + Font.toJson(obj.markerFont, w); + w.prop("mainGlyphColor"); + Color.toJson(obj.mainGlyphColor, w); + w.prop("secondaryGlyphColor"); + Color.toJson(obj.secondaryGlyphColor, w); + w.prop("scoreInfoColor"); + Color.toJson(obj.scoreInfoColor, w); + w.endObject(); } - public static setProperty(obj: RenderingResources, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: RenderingResources, property: string, r: IJsonReader): boolean { switch (property) { case "copyrightfont": - obj.copyrightFont = (Font.fromJson(reader)!); + obj.copyrightFont = (Font.fromJson(r)!); return true; case "titlefont": - obj.titleFont = (Font.fromJson(reader)!); + obj.titleFont = (Font.fromJson(r)!); return true; case "subtitlefont": - obj.subTitleFont = (Font.fromJson(reader)!); + obj.subTitleFont = (Font.fromJson(r)!); return true; case "wordsfont": - obj.wordsFont = (Font.fromJson(reader)!); + obj.wordsFont = (Font.fromJson(r)!); return true; case "effectfont": - obj.effectFont = (Font.fromJson(reader)!); + obj.effectFont = (Font.fromJson(r)!); return true; case "fretboardnumberfont": - obj.fretboardNumberFont = (Font.fromJson(reader)!); + obj.fretboardNumberFont = (Font.fromJson(r)!); return true; case "tablaturefont": - obj.tablatureFont = (Font.fromJson(reader)!); + obj.tablatureFont = (Font.fromJson(r)!); return true; case "gracefont": - obj.graceFont = (Font.fromJson(reader)!); + obj.graceFont = (Font.fromJson(r)!); return true; case "stafflinecolor": - obj.staffLineColor = (Color.fromJson(reader)!); + obj.staffLineColor = (Color.fromJson(r)!); return true; case "barseparatorcolor": - obj.barSeparatorColor = (Color.fromJson(reader)!); + obj.barSeparatorColor = (Color.fromJson(r)!); return true; case "barnumberfont": - obj.barNumberFont = (Font.fromJson(reader)!); + obj.barNumberFont = (Font.fromJson(r)!); return true; case "barnumbercolor": - obj.barNumberColor = (Color.fromJson(reader)!); + obj.barNumberColor = (Color.fromJson(r)!); return true; case "fingeringfont": - obj.fingeringFont = (Font.fromJson(reader)!); + obj.fingeringFont = (Font.fromJson(r)!); return true; case "markerfont": - obj.markerFont = (Font.fromJson(reader)!); + obj.markerFont = (Font.fromJson(r)!); return true; case "mainglyphcolor": - obj.mainGlyphColor = (Color.fromJson(reader)!); + obj.mainGlyphColor = (Color.fromJson(r)!); return true; case "secondaryglyphcolor": - obj.secondaryGlyphColor = (Color.fromJson(reader)!); + obj.secondaryGlyphColor = (Color.fromJson(r)!); return true; case "scoreinfocolor": - obj.scoreInfoColor = (Color.fromJson(reader)!); + obj.scoreInfoColor = (Color.fromJson(r)!); return true; } return false; diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts index 4c11fb7ec..123542620 100644 --- a/src/generated/SettingsSerializer.ts +++ b/src/generated/SettingsSerializer.ts @@ -13,95 +13,95 @@ import { NotationSettingsSerializer } from "@src/generated/NotationSettingsSeria import { ImporterSettingsSerializer } from "@src/generated/ImporterSettingsSerializer"; import { PlayerSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; export class SettingsSerializer { - public static fromJson(obj: Settings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Settings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Settings | null, writer: IJsonWriter): void { + public static toJson(obj: Settings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("core"); - CoreSettingsSerializer.toJson(obj.core, writer); - writer.writePropertyName("display"); - DisplaySettingsSerializer.toJson(obj.display, writer); - writer.writePropertyName("notation"); - NotationSettingsSerializer.toJson(obj.notation, writer); - writer.writePropertyName("importer"); - ImporterSettingsSerializer.toJson(obj.importer, writer); - writer.writePropertyName("player"); - PlayerSettingsSerializer.toJson(obj.player, writer); - writer.writeEndObject(); + w.startObject(); + w.prop("core"); + CoreSettingsSerializer.toJson(obj.core, w); + w.prop("display"); + DisplaySettingsSerializer.toJson(obj.display, w); + w.prop("notation"); + NotationSettingsSerializer.toJson(obj.notation, w); + w.prop("importer"); + ImporterSettingsSerializer.toJson(obj.importer, w); + w.prop("player"); + PlayerSettingsSerializer.toJson(obj.player, w); + w.endObject(); } - public static setProperty(obj: Settings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Settings, property: string, r: IJsonReader): boolean { switch (property) { } if (["core", ""].indexOf(property) >= 0) { - CoreSettingsSerializer.fromJson(obj.core, reader); + CoreSettingsSerializer.fromJson(obj.core, r); return true; } else { for (const c of ["core", ""]) { if (property.indexOf(c) === 0) { - if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), reader)) { + if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), r)) { return true; } } } } if (["display", ""].indexOf(property) >= 0) { - DisplaySettingsSerializer.fromJson(obj.display, reader); + DisplaySettingsSerializer.fromJson(obj.display, r); return true; } else { for (const c of ["display", ""]) { if (property.indexOf(c) === 0) { - if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), reader)) { + if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), r)) { return true; } } } } if (["notation"].indexOf(property) >= 0) { - NotationSettingsSerializer.fromJson(obj.notation, reader); + NotationSettingsSerializer.fromJson(obj.notation, r); return true; } else { for (const c of ["notation"]) { if (property.indexOf(c) === 0) { - if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), reader)) { + if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), r)) { return true; } } } } if (["importer"].indexOf(property) >= 0) { - ImporterSettingsSerializer.fromJson(obj.importer, reader); + ImporterSettingsSerializer.fromJson(obj.importer, r); return true; } else { for (const c of ["importer"]) { if (property.indexOf(c) === 0) { - if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), reader)) { + if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), r)) { return true; } } } } if (["player"].indexOf(property) >= 0) { - PlayerSettingsSerializer.fromJson(obj.player, reader); + PlayerSettingsSerializer.fromJson(obj.player, r); return true; } else { for (const c of ["player"]) { if (property.indexOf(c) === 0) { - if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), reader)) { + if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), r)) { return true; } } diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts index d93a1a363..74ae5ec00 100644 --- a/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -8,38 +8,38 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class SlidePlaybackSettingsSerializer { - public static fromJson(obj: SlidePlaybackSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: SlidePlaybackSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: SlidePlaybackSettings | null, writer: IJsonWriter): void { + public static toJson(obj: SlidePlaybackSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("simpleSlidePitchOffset"); - writer.writeNumber(obj.simpleSlidePitchOffset); - writer.writePropertyName("simpleSlideDurationRatio"); - writer.writeNumber(obj.simpleSlideDurationRatio); - writer.writePropertyName("shiftSlideDurationRatio"); - writer.writeNumber(obj.shiftSlideDurationRatio); - writer.writeEndObject(); + w.startObject(); + w.prop("simpleSlidePitchOffset"); + w.number(obj.simpleSlidePitchOffset); + w.prop("simpleSlideDurationRatio"); + w.number(obj.simpleSlideDurationRatio); + w.prop("shiftSlideDurationRatio"); + w.number(obj.shiftSlideDurationRatio); + w.endObject(); } - public static setProperty(obj: SlidePlaybackSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: SlidePlaybackSettings, property: string, r: IJsonReader): boolean { switch (property) { case "simpleslidepitchoffset": - obj.simpleSlidePitchOffset = (reader.readNumber()!); + obj.simpleSlidePitchOffset = (r.number()!); return true; case "simpleslidedurationratio": - obj.simpleSlideDurationRatio = (reader.readNumber()!); + obj.simpleSlideDurationRatio = (r.number()!); return true; case "shiftslidedurationratio": - obj.shiftSlideDurationRatio = (reader.readNumber()!); + obj.shiftSlideDurationRatio = (r.number()!); return true; } return false; diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts index f953caf48..8b0cf803e 100644 --- a/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -8,63 +8,63 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class VibratoPlaybackSettingsSerializer { - public static fromJson(obj: VibratoPlaybackSettings, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: VibratoPlaybackSettings, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: VibratoPlaybackSettings | null, writer: IJsonWriter): void { + public static toJson(obj: VibratoPlaybackSettings | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("noteWideLength"); - writer.writeNumber(obj.noteWideLength); - writer.writePropertyName("noteWideAmplitude"); - writer.writeNumber(obj.noteWideAmplitude); - writer.writePropertyName("noteSlightLength"); - writer.writeNumber(obj.noteSlightLength); - writer.writePropertyName("noteSlightAmplitude"); - writer.writeNumber(obj.noteSlightAmplitude); - writer.writePropertyName("beatWideLength"); - writer.writeNumber(obj.beatWideLength); - writer.writePropertyName("beatWideAmplitude"); - writer.writeNumber(obj.beatWideAmplitude); - writer.writePropertyName("beatSlightLength"); - writer.writeNumber(obj.beatSlightLength); - writer.writePropertyName("beatSlightAmplitude"); - writer.writeNumber(obj.beatSlightAmplitude); - writer.writeEndObject(); + w.startObject(); + w.prop("noteWideLength"); + w.number(obj.noteWideLength); + w.prop("noteWideAmplitude"); + w.number(obj.noteWideAmplitude); + w.prop("noteSlightLength"); + w.number(obj.noteSlightLength); + w.prop("noteSlightAmplitude"); + w.number(obj.noteSlightAmplitude); + w.prop("beatWideLength"); + w.number(obj.beatWideLength); + w.prop("beatWideAmplitude"); + w.number(obj.beatWideAmplitude); + w.prop("beatSlightLength"); + w.number(obj.beatSlightLength); + w.prop("beatSlightAmplitude"); + w.number(obj.beatSlightAmplitude); + w.endObject(); } - public static setProperty(obj: VibratoPlaybackSettings, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: VibratoPlaybackSettings, property: string, r: IJsonReader): boolean { switch (property) { case "notewidelength": - obj.noteWideLength = (reader.readNumber()!); + obj.noteWideLength = (r.number()!); return true; case "notewideamplitude": - obj.noteWideAmplitude = (reader.readNumber()!); + obj.noteWideAmplitude = (r.number()!); return true; case "noteslightlength": - obj.noteSlightLength = (reader.readNumber()!); + obj.noteSlightLength = (r.number()!); return true; case "noteslightamplitude": - obj.noteSlightAmplitude = (reader.readNumber()!); + obj.noteSlightAmplitude = (r.number()!); return true; case "beatwidelength": - obj.beatWideLength = (reader.readNumber()!); + obj.beatWideLength = (r.number()!); return true; case "beatwideamplitude": - obj.beatWideAmplitude = (reader.readNumber()!); + obj.beatWideAmplitude = (r.number()!); return true; case "beatslightlength": - obj.beatSlightLength = (reader.readNumber()!); + obj.beatSlightLength = (r.number()!); return true; case "beatslightamplitude": - obj.beatSlightAmplitude = (reader.readNumber()!); + obj.beatSlightAmplitude = (r.number()!); return true; } return false; diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts index e5d48b0f7..37f356a0a 100644 --- a/src/generated/model/AutomationSerializer.ts +++ b/src/generated/model/AutomationSerializer.ts @@ -9,48 +9,48 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { AutomationType } from "@src/model/Automation"; export class AutomationSerializer { - public static fromJson(obj: Automation, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Automation, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Automation | null, writer: IJsonWriter): void { + public static toJson(obj: Automation | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("isLinear"); - writer.writeBoolean(obj.isLinear); - writer.writePropertyName("type"); - writer.writeEnum(obj.type); - writer.writePropertyName("value"); - writer.writeNumber(obj.value); - writer.writePropertyName("ratioPosition"); - writer.writeNumber(obj.ratioPosition); - writer.writePropertyName("text"); - writer.writeString(obj.text); - writer.writeEndObject(); + w.startObject(); + w.prop("isLinear"); + w.boolean(obj.isLinear); + w.prop("type"); + w.enum(obj.type); + w.prop("value"); + w.number(obj.value); + w.prop("ratioPosition"); + w.number(obj.ratioPosition); + w.prop("text"); + w.string(obj.text); + w.endObject(); } - public static setProperty(obj: Automation, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Automation, property: string, r: IJsonReader): boolean { switch (property) { case "islinear": - obj.isLinear = (reader.readBoolean()!); + obj.isLinear = (r.boolean()!); return true; case "type": - obj.type = (reader.readEnum(AutomationType)!); + obj.type = (r.enum(AutomationType)!); return true; case "value": - obj.value = (reader.readNumber()!); + obj.value = (r.number()!); return true; case "ratioposition": - obj.ratioPosition = (reader.readNumber()!); + obj.ratioPosition = (r.number()!); return true; case "text": - obj.text = (reader.readString()!); + obj.text = (r.string()!); return true; } return false; diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index d6405ab4e..d33e21229 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -13,62 +13,62 @@ import { Ottavia } from "@src/model/Ottavia"; import { Voice } from "@src/model/Voice"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { - public static fromJson(obj: Bar, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Bar, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Bar | null, writer: IJsonWriter): void { + public static toJson(obj: Bar | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("id"); - writer.writeNumber(obj.id); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("clef"); - writer.writeEnum(obj.clef); - writer.writePropertyName("clefOttava"); - writer.writeEnum(obj.clefOttava); - writer.writePropertyName("voices"); - writer.writeStartArray(); + w.startObject(); + w.prop("id"); + w.number(obj.id); + w.prop("index"); + w.number(obj.index); + w.prop("clef"); + w.enum(obj.clef); + w.prop("clefOttava"); + w.enum(obj.clefOttava); + w.prop("voices"); + w.startArray(); for (const i of obj.voices) { - VoiceSerializer.toJson(i, writer); + VoiceSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("simileMark"); - writer.writeEnum(obj.simileMark); - writer.writeEndObject(); + w.endArray(); + w.prop("simileMark"); + w.enum(obj.simileMark); + w.endObject(); } - public static setProperty(obj: Bar, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Bar, property: string, r: IJsonReader): boolean { switch (property) { case "id": - obj.id = (reader.readNumber()!); + obj.id = (r.number()!); return true; case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "clef": - obj.clef = (reader.readEnum(Clef)!); + obj.clef = (r.enum(Clef)!); return true; case "clefottava": - obj.clefOttava = (reader.readEnum(Ottavia)!); + obj.clefOttava = (r.enum(Ottavia)!); return true; case "voices": obj.voices = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Voice(); - VoiceSerializer.fromJson(i, reader) + VoiceSerializer.fromJson(i, r) obj.addVoice(i); } return true; case "similemark": - obj.simileMark = (reader.readEnum(SimileMark)!); + obj.simileMark = (r.enum(SimileMark)!); return true; } return false; diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index 3517416ba..f8e2d8850 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -26,255 +26,255 @@ import { DynamicValue } from "@src/model/DynamicValue"; import { BeamDirection } from "@src/rendering/utils/BeamDirection"; import { BeatBeamingMode } from "@src/model/Beat"; export class BeatSerializer { - public static fromJson(obj: Beat, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Beat, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Beat | null, writer: IJsonWriter): void { + public static toJson(obj: Beat | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("id"); - writer.writeNumber(obj.id); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("notes"); - writer.writeStartArray(); + w.startObject(); + w.prop("id"); + w.number(obj.id); + w.prop("index"); + w.number(obj.index); + w.prop("notes"); + w.startArray(); for (const i of obj.notes) { - NoteSerializer.toJson(i, writer); + NoteSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("isEmpty"); - writer.writeBoolean(obj.isEmpty); - writer.writePropertyName("whammyStyle"); - writer.writeEnum(obj.whammyStyle); - writer.writePropertyName("ottava"); - writer.writeEnum(obj.ottava); - writer.writePropertyName("isLegatoOrigin"); - writer.writeBoolean(obj.isLegatoOrigin); - writer.writePropertyName("duration"); - writer.writeEnum(obj.duration); - writer.writePropertyName("isLetRing"); - writer.writeBoolean(obj.isLetRing); - writer.writePropertyName("isPalmMute"); - writer.writeBoolean(obj.isPalmMute); - writer.writePropertyName("automations"); - writer.writeStartArray(); + w.endArray(); + w.prop("isEmpty"); + w.boolean(obj.isEmpty); + w.prop("whammyStyle"); + w.enum(obj.whammyStyle); + w.prop("ottava"); + w.enum(obj.ottava); + w.prop("isLegatoOrigin"); + w.boolean(obj.isLegatoOrigin); + w.prop("duration"); + w.enum(obj.duration); + w.prop("isLetRing"); + w.boolean(obj.isLetRing); + w.prop("isPalmMute"); + w.boolean(obj.isPalmMute); + w.prop("automations"); + w.startArray(); for (const i of obj.automations) { - AutomationSerializer.toJson(i, writer); + AutomationSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("dots"); - writer.writeNumber(obj.dots); - writer.writePropertyName("fadeIn"); - writer.writeBoolean(obj.fadeIn); - writer.writePropertyName("lyrics"); - writer.writeStringArray(obj.lyrics); - writer.writePropertyName("hasRasgueado"); - writer.writeBoolean(obj.hasRasgueado); - writer.writePropertyName("pop"); - writer.writeBoolean(obj.pop); - writer.writePropertyName("slap"); - writer.writeBoolean(obj.slap); - writer.writePropertyName("tap"); - writer.writeBoolean(obj.tap); - writer.writePropertyName("text"); - writer.writeString(obj.text); - writer.writePropertyName("brushType"); - writer.writeEnum(obj.brushType); - writer.writePropertyName("brushDuration"); - writer.writeNumber(obj.brushDuration); - writer.writePropertyName("tupletDenominator"); - writer.writeNumber(obj.tupletDenominator); - writer.writePropertyName("tupletNumerator"); - writer.writeNumber(obj.tupletNumerator); - writer.writePropertyName("isContinuedWhammy"); - writer.writeBoolean(obj.isContinuedWhammy); - writer.writePropertyName("whammyBarType"); - writer.writeEnum(obj.whammyBarType); - writer.writePropertyName("whammyBarPoints"); - writer.writeStartArray(); + w.endArray(); + w.prop("dots"); + w.number(obj.dots); + w.prop("fadeIn"); + w.boolean(obj.fadeIn); + w.prop("lyrics"); + w.stringArray(obj.lyrics); + w.prop("hasRasgueado"); + w.boolean(obj.hasRasgueado); + w.prop("pop"); + w.boolean(obj.pop); + w.prop("slap"); + w.boolean(obj.slap); + w.prop("tap"); + w.boolean(obj.tap); + w.prop("text"); + w.string(obj.text); + w.prop("brushType"); + w.enum(obj.brushType); + w.prop("brushDuration"); + w.number(obj.brushDuration); + w.prop("tupletDenominator"); + w.number(obj.tupletDenominator); + w.prop("tupletNumerator"); + w.number(obj.tupletNumerator); + w.prop("isContinuedWhammy"); + w.boolean(obj.isContinuedWhammy); + w.prop("whammyBarType"); + w.enum(obj.whammyBarType); + w.prop("whammyBarPoints"); + w.startArray(); for (const i of obj.whammyBarPoints) { - BendPointSerializer.toJson(i, writer); + BendPointSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("vibrato"); - writer.writeEnum(obj.vibrato); - writer.writePropertyName("chordId"); - writer.writeString(obj.chordId); - writer.writePropertyName("graceType"); - writer.writeEnum(obj.graceType); - writer.writePropertyName("pickStroke"); - writer.writeEnum(obj.pickStroke); - writer.writePropertyName("tremoloSpeed"); - writer.writeEnum(obj.tremoloSpeed); - writer.writePropertyName("crescendo"); - writer.writeEnum(obj.crescendo); - writer.writePropertyName("displayStart"); - writer.writeNumber(obj.displayStart); - writer.writePropertyName("playbackStart"); - writer.writeNumber(obj.playbackStart); - writer.writePropertyName("displayDuration"); - writer.writeNumber(obj.displayDuration); - writer.writePropertyName("playbackDuration"); - writer.writeNumber(obj.playbackDuration); - writer.writePropertyName("dynamics"); - writer.writeEnum(obj.dynamics); - writer.writePropertyName("invertBeamDirection"); - writer.writeBoolean(obj.invertBeamDirection); - writer.writePropertyName("preferredBeamDirection"); - writer.writeEnum(obj.preferredBeamDirection); - writer.writePropertyName("isEffectSlurOrigin"); - writer.writeBoolean(obj.isEffectSlurOrigin); - writer.writePropertyName("beamingMode"); - writer.writeEnum(obj.beamingMode); - writer.writeEndObject(); + w.endArray(); + w.prop("vibrato"); + w.enum(obj.vibrato); + w.prop("chordId"); + w.string(obj.chordId); + w.prop("graceType"); + w.enum(obj.graceType); + w.prop("pickStroke"); + w.enum(obj.pickStroke); + w.prop("tremoloSpeed"); + w.enum(obj.tremoloSpeed); + w.prop("crescendo"); + w.enum(obj.crescendo); + w.prop("displayStart"); + w.number(obj.displayStart); + w.prop("playbackStart"); + w.number(obj.playbackStart); + w.prop("displayDuration"); + w.number(obj.displayDuration); + w.prop("playbackDuration"); + w.number(obj.playbackDuration); + w.prop("dynamics"); + w.enum(obj.dynamics); + w.prop("invertBeamDirection"); + w.boolean(obj.invertBeamDirection); + w.prop("preferredBeamDirection"); + w.enum(obj.preferredBeamDirection); + w.prop("isEffectSlurOrigin"); + w.boolean(obj.isEffectSlurOrigin); + w.prop("beamingMode"); + w.enum(obj.beamingMode); + w.endObject(); } - public static setProperty(obj: Beat, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Beat, property: string, r: IJsonReader): boolean { switch (property) { case "id": - obj.id = (reader.readNumber()!); + obj.id = (r.number()!); return true; case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "notes": obj.notes = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Note(); - NoteSerializer.fromJson(i, reader) + NoteSerializer.fromJson(i, r) obj.addNote(i); } return true; case "isempty": - obj.isEmpty = (reader.readBoolean()!); + obj.isEmpty = (r.boolean()!); return true; case "whammystyle": - obj.whammyStyle = (reader.readEnum(BendStyle)!); + obj.whammyStyle = (r.enum(BendStyle)!); return true; case "ottava": - obj.ottava = (reader.readEnum(Ottavia)!); + obj.ottava = (r.enum(Ottavia)!); return true; case "islegatoorigin": - obj.isLegatoOrigin = (reader.readBoolean()!); + obj.isLegatoOrigin = (r.boolean()!); return true; case "duration": - obj.duration = (reader.readEnum(Duration)!); + obj.duration = (r.enum(Duration)!); return true; case "isletring": - obj.isLetRing = (reader.readBoolean()!); + obj.isLetRing = (r.boolean()!); return true; case "ispalmmute": - obj.isPalmMute = (reader.readBoolean()!); + obj.isPalmMute = (r.boolean()!); return true; case "automations": obj.automations = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Automation(); - AutomationSerializer.fromJson(i, reader) + AutomationSerializer.fromJson(i, r) obj.automations.push(i); } return true; case "dots": - obj.dots = (reader.readNumber()!); + obj.dots = (r.number()!); return true; case "fadein": - obj.fadeIn = (reader.readBoolean()!); + obj.fadeIn = (r.boolean()!); return true; case "lyrics": - obj.lyrics = reader.readStringArray(); + obj.lyrics = r.stringArray(); return true; case "hasrasgueado": - obj.hasRasgueado = (reader.readBoolean()!); + obj.hasRasgueado = (r.boolean()!); return true; case "pop": - obj.pop = (reader.readBoolean()!); + obj.pop = (r.boolean()!); return true; case "slap": - obj.slap = (reader.readBoolean()!); + obj.slap = (r.boolean()!); return true; case "tap": - obj.tap = (reader.readBoolean()!); + obj.tap = (r.boolean()!); return true; case "text": - obj.text = reader.readString(); + obj.text = r.string(); return true; case "brushtype": - obj.brushType = (reader.readEnum(BrushType)!); + obj.brushType = (r.enum(BrushType)!); return true; case "brushduration": - obj.brushDuration = (reader.readNumber()!); + obj.brushDuration = (r.number()!); return true; case "tupletdenominator": - obj.tupletDenominator = (reader.readNumber()!); + obj.tupletDenominator = (r.number()!); return true; case "tupletnumerator": - obj.tupletNumerator = (reader.readNumber()!); + obj.tupletNumerator = (r.number()!); return true; case "iscontinuedwhammy": - obj.isContinuedWhammy = (reader.readBoolean()!); + obj.isContinuedWhammy = (r.boolean()!); return true; case "whammybartype": - obj.whammyBarType = (reader.readEnum(WhammyType)!); + obj.whammyBarType = (r.enum(WhammyType)!); return true; case "whammybarpoints": obj.whammyBarPoints = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new BendPoint(); - BendPointSerializer.fromJson(i, reader) + BendPointSerializer.fromJson(i, r) obj.addWhammyBarPoint(i); } return true; case "vibrato": - obj.vibrato = (reader.readEnum(VibratoType)!); + obj.vibrato = (r.enum(VibratoType)!); return true; case "chordid": - obj.chordId = reader.readString(); + obj.chordId = r.string(); return true; case "gracetype": - obj.graceType = (reader.readEnum(GraceType)!); + obj.graceType = (r.enum(GraceType)!); return true; case "pickstroke": - obj.pickStroke = (reader.readEnum(PickStroke)!); + obj.pickStroke = (r.enum(PickStroke)!); return true; case "tremolospeed": - obj.tremoloSpeed = reader.readEnum(Duration); + obj.tremoloSpeed = r.enum(Duration); return true; case "crescendo": - obj.crescendo = (reader.readEnum(CrescendoType)!); + obj.crescendo = (r.enum(CrescendoType)!); return true; case "displaystart": - obj.displayStart = (reader.readNumber()!); + obj.displayStart = (r.number()!); return true; case "playbackstart": - obj.playbackStart = (reader.readNumber()!); + obj.playbackStart = (r.number()!); return true; case "displayduration": - obj.displayDuration = (reader.readNumber()!); + obj.displayDuration = (r.number()!); return true; case "playbackduration": - obj.playbackDuration = (reader.readNumber()!); + obj.playbackDuration = (r.number()!); return true; case "dynamics": - obj.dynamics = (reader.readEnum(DynamicValue)!); + obj.dynamics = (r.enum(DynamicValue)!); return true; case "invertbeamdirection": - obj.invertBeamDirection = (reader.readBoolean()!); + obj.invertBeamDirection = (r.boolean()!); return true; case "preferredbeamdirection": - obj.preferredBeamDirection = reader.readEnum(BeamDirection); + obj.preferredBeamDirection = r.enum(BeamDirection); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = (reader.readBoolean()!); + obj.isEffectSlurOrigin = (r.boolean()!); return true; case "beamingmode": - obj.beamingMode = (reader.readEnum(BeatBeamingMode)!); + obj.beamingMode = (r.enum(BeatBeamingMode)!); return true; } return false; diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts index f16187d42..fffea298c 100644 --- a/src/generated/model/BendPointSerializer.ts +++ b/src/generated/model/BendPointSerializer.ts @@ -8,33 +8,33 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class BendPointSerializer { - public static fromJson(obj: BendPoint, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: BendPoint, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: BendPoint | null, writer: IJsonWriter): void { + public static toJson(obj: BendPoint | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("offset"); - writer.writeNumber(obj.offset); - writer.writePropertyName("value"); - writer.writeNumber(obj.value); - writer.writeEndObject(); + w.startObject(); + w.prop("offset"); + w.number(obj.offset); + w.prop("value"); + w.number(obj.value); + w.endObject(); } - public static setProperty(obj: BendPoint, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: BendPoint, property: string, r: IJsonReader): boolean { switch (property) { case "offset": - obj.offset = (reader.readNumber()!); + obj.offset = (r.number()!); return true; case "value": - obj.value = (reader.readNumber()!); + obj.value = (r.number()!); return true; } return false; diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts index 7414d7a91..91db145b4 100644 --- a/src/generated/model/ChordSerializer.ts +++ b/src/generated/model/ChordSerializer.ts @@ -8,58 +8,58 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class ChordSerializer { - public static fromJson(obj: Chord, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Chord, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Chord | null, writer: IJsonWriter): void { + public static toJson(obj: Chord | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("name"); - writer.writeString(obj.name); - writer.writePropertyName("firstFret"); - writer.writeNumber(obj.firstFret); - writer.writePropertyName("strings"); - writer.writeNumberArray(obj.strings); - writer.writePropertyName("barreFrets"); - writer.writeNumberArray(obj.barreFrets); - writer.writePropertyName("showName"); - writer.writeBoolean(obj.showName); - writer.writePropertyName("showDiagram"); - writer.writeBoolean(obj.showDiagram); - writer.writePropertyName("showFingering"); - writer.writeBoolean(obj.showFingering); - writer.writeEndObject(); + w.startObject(); + w.prop("name"); + w.string(obj.name); + w.prop("firstFret"); + w.number(obj.firstFret); + w.prop("strings"); + w.numberArray(obj.strings); + w.prop("barreFrets"); + w.numberArray(obj.barreFrets); + w.prop("showName"); + w.boolean(obj.showName); + w.prop("showDiagram"); + w.boolean(obj.showDiagram); + w.prop("showFingering"); + w.boolean(obj.showFingering); + w.endObject(); } - public static setProperty(obj: Chord, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Chord, property: string, r: IJsonReader): boolean { switch (property) { case "name": - obj.name = (reader.readString()!); + obj.name = (r.string()!); return true; case "firstfret": - obj.firstFret = (reader.readNumber()!); + obj.firstFret = (r.number()!); return true; case "strings": - obj.strings = (reader.readNumberArray()!); + obj.strings = (r.numberArray()!); return true; case "barrefrets": - obj.barreFrets = (reader.readNumberArray()!); + obj.barreFrets = (r.numberArray()!); return true; case "showname": - obj.showName = (reader.readBoolean()!); + obj.showName = (r.boolean()!); return true; case "showdiagram": - obj.showDiagram = (reader.readBoolean()!); + obj.showDiagram = (r.boolean()!); return true; case "showfingering": - obj.showFingering = (reader.readBoolean()!); + obj.showFingering = (r.boolean()!); return true; } return false; diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts index 8dded0b76..9b053bf5a 100644 --- a/src/generated/model/FermataSerializer.ts +++ b/src/generated/model/FermataSerializer.ts @@ -9,33 +9,33 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; import { FermataType } from "@src/model/Fermata"; export class FermataSerializer { - public static fromJson(obj: Fermata, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Fermata, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Fermata | null, writer: IJsonWriter): void { + public static toJson(obj: Fermata | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("type"); - writer.writeEnum(obj.type); - writer.writePropertyName("length"); - writer.writeNumber(obj.length); - writer.writeEndObject(); + w.startObject(); + w.prop("type"); + w.enum(obj.type); + w.prop("length"); + w.number(obj.length); + w.endObject(); } - public static setProperty(obj: Fermata, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Fermata, property: string, r: IJsonReader): boolean { switch (property) { case "type": - obj.type = (reader.readEnum(FermataType)!); + obj.type = (r.enum(FermataType)!); return true; case "length": - obj.length = (reader.readNumber()!); + obj.length = (r.number()!); return true; } return false; diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts index 737f46970..de9a51c1c 100644 --- a/src/generated/model/InstrumentArticulationSerializer.ts +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -10,58 +10,58 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; import { TextBaseline } from "@src/platform/ICanvas"; export class InstrumentArticulationSerializer { - public static fromJson(obj: InstrumentArticulation, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: InstrumentArticulation, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: InstrumentArticulation | null, writer: IJsonWriter): void { + public static toJson(obj: InstrumentArticulation | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("staffLine"); - writer.writeNumber(obj.staffLine); - writer.writePropertyName("noteHeadDefault"); - writer.writeEnum(obj.noteHeadDefault); - writer.writePropertyName("noteHeadHalf"); - writer.writeEnum(obj.noteHeadHalf); - writer.writePropertyName("noteHeadWhole"); - writer.writeEnum(obj.noteHeadWhole); - writer.writePropertyName("techniqueSymbol"); - writer.writeEnum(obj.techniqueSymbol); - writer.writePropertyName("techniqueSymbolPlacement"); - writer.writeEnum(obj.techniqueSymbolPlacement); - writer.writePropertyName("outputMidiNumber"); - writer.writeNumber(obj.outputMidiNumber); - writer.writeEndObject(); + w.startObject(); + w.prop("staffLine"); + w.number(obj.staffLine); + w.prop("noteHeadDefault"); + w.enum(obj.noteHeadDefault); + w.prop("noteHeadHalf"); + w.enum(obj.noteHeadHalf); + w.prop("noteHeadWhole"); + w.enum(obj.noteHeadWhole); + w.prop("techniqueSymbol"); + w.enum(obj.techniqueSymbol); + w.prop("techniqueSymbolPlacement"); + w.enum(obj.techniqueSymbolPlacement); + w.prop("outputMidiNumber"); + w.number(obj.outputMidiNumber); + w.endObject(); } - public static setProperty(obj: InstrumentArticulation, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: InstrumentArticulation, property: string, r: IJsonReader): boolean { switch (property) { case "staffline": - obj.staffLine = (reader.readNumber()!); + obj.staffLine = (r.number()!); return true; case "noteheaddefault": - obj.noteHeadDefault = (reader.readEnum(MusicFontSymbol)!); + obj.noteHeadDefault = (r.enum(MusicFontSymbol)!); return true; case "noteheadhalf": - obj.noteHeadHalf = (reader.readEnum(MusicFontSymbol)!); + obj.noteHeadHalf = (r.enum(MusicFontSymbol)!); return true; case "noteheadwhole": - obj.noteHeadWhole = (reader.readEnum(MusicFontSymbol)!); + obj.noteHeadWhole = (r.enum(MusicFontSymbol)!); return true; case "techniquesymbol": - obj.techniqueSymbol = (reader.readEnum(MusicFontSymbol)!); + obj.techniqueSymbol = (r.enum(MusicFontSymbol)!); return true; case "techniquesymbolplacement": - obj.techniqueSymbolPlacement = (reader.readEnum(TextBaseline)!); + obj.techniqueSymbolPlacement = (r.enum(TextBaseline)!); return true; case "outputmidinumber": - obj.outputMidiNumber = (reader.readNumber()!); + obj.outputMidiNumber = (r.number()!); return true; } return false; diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index 3ce550977..80041db70 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -17,118 +17,118 @@ import { Section } from "@src/model/Section"; import { Automation } from "@src/model/Automation"; import { Fermata } from "@src/model/Fermata"; export class MasterBarSerializer { - public static fromJson(obj: MasterBar, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: MasterBar, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: MasterBar | null, writer: IJsonWriter): void { + public static toJson(obj: MasterBar | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("alternateEndings"); - writer.writeNumber(obj.alternateEndings); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("keySignature"); - writer.writeEnum(obj.keySignature); - writer.writePropertyName("keySignatureType"); - writer.writeEnum(obj.keySignatureType); - writer.writePropertyName("isDoubleBar"); - writer.writeBoolean(obj.isDoubleBar); - writer.writePropertyName("isRepeatStart"); - writer.writeBoolean(obj.isRepeatStart); - writer.writePropertyName("repeatCount"); - writer.writeNumber(obj.repeatCount); - writer.writePropertyName("timeSignatureNumerator"); - writer.writeNumber(obj.timeSignatureNumerator); - writer.writePropertyName("timeSignatureDenominator"); - writer.writeNumber(obj.timeSignatureDenominator); - writer.writePropertyName("timeSignatureCommon"); - writer.writeBoolean(obj.timeSignatureCommon); - writer.writePropertyName("tripletFeel"); - writer.writeEnum(obj.tripletFeel); - writer.writePropertyName("section"); + w.startObject(); + w.prop("alternateEndings"); + w.number(obj.alternateEndings); + w.prop("index"); + w.number(obj.index); + w.prop("keySignature"); + w.enum(obj.keySignature); + w.prop("keySignatureType"); + w.enum(obj.keySignatureType); + w.prop("isDoubleBar"); + w.boolean(obj.isDoubleBar); + w.prop("isRepeatStart"); + w.boolean(obj.isRepeatStart); + w.prop("repeatCount"); + w.number(obj.repeatCount); + w.prop("timeSignatureNumerator"); + w.number(obj.timeSignatureNumerator); + w.prop("timeSignatureDenominator"); + w.number(obj.timeSignatureDenominator); + w.prop("timeSignatureCommon"); + w.boolean(obj.timeSignatureCommon); + w.prop("tripletFeel"); + w.enum(obj.tripletFeel); + w.prop("section"); if (obj.section) { - SectionSerializer.toJson(obj.section, writer); + SectionSerializer.toJson(obj.section, w); } else - writer.writeNull(); - writer.writePropertyName("tempoAutomation"); + w.null(); + w.prop("tempoAutomation"); if (obj.tempoAutomation) { - AutomationSerializer.toJson(obj.tempoAutomation, writer); + AutomationSerializer.toJson(obj.tempoAutomation, w); } else - writer.writeNull(); - writer.writePropertyName("fermata"); - writer.writeStartObject(); - obj.fermata.forEach((v, k) => { writer.writePropertyName(k); FermataSerializer.toJson(v, writer); }); - writer.writeEndObject(); - writer.writePropertyName("start"); - writer.writeNumber(obj.start); - writer.writePropertyName("isAnacrusis"); - writer.writeBoolean(obj.isAnacrusis); - writer.writeEndObject(); + w.null(); + w.prop("fermata"); + w.startObject(); + obj.fermata.forEach((v, k) => { w.prop(k); FermataSerializer.toJson(v, w); }); + w.endObject(); + w.prop("start"); + w.number(obj.start); + w.prop("isAnacrusis"); + w.boolean(obj.isAnacrusis); + w.endObject(); } - public static setProperty(obj: MasterBar, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: MasterBar, property: string, r: IJsonReader): boolean { switch (property) { case "alternateendings": - obj.alternateEndings = (reader.readNumber()!); + obj.alternateEndings = (r.number()!); return true; case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "keysignature": - obj.keySignature = (reader.readEnum(KeySignature)!); + obj.keySignature = (r.enum(KeySignature)!); return true; case "keysignaturetype": - obj.keySignatureType = (reader.readEnum(KeySignatureType)!); + obj.keySignatureType = (r.enum(KeySignatureType)!); return true; case "isdoublebar": - obj.isDoubleBar = (reader.readBoolean()!); + obj.isDoubleBar = (r.boolean()!); return true; case "isrepeatstart": - obj.isRepeatStart = (reader.readBoolean()!); + obj.isRepeatStart = (r.boolean()!); return true; case "repeatcount": - obj.repeatCount = (reader.readNumber()!); + obj.repeatCount = (r.number()!); return true; case "timesignaturenumerator": - obj.timeSignatureNumerator = (reader.readNumber()!); + obj.timeSignatureNumerator = (r.number()!); return true; case "timesignaturedenominator": - obj.timeSignatureDenominator = (reader.readNumber()!); + obj.timeSignatureDenominator = (r.number()!); return true; case "timesignaturecommon": - obj.timeSignatureCommon = (reader.readBoolean()!); + obj.timeSignatureCommon = (r.boolean()!); return true; case "tripletfeel": - obj.tripletFeel = (reader.readEnum(TripletFeel)!); + obj.tripletFeel = (r.enum(TripletFeel)!); return true; case "fermata": obj.fermata = new Map(); - while (reader.nextProperty()) { + while (r.nextProp()) { const i = new Fermata(); - FermataSerializer.fromJson(i, reader); - obj.fermata.set(reader.readPropertyNameAsNumber(), i); + FermataSerializer.fromJson(i, r); + obj.fermata.set(r.numberProp(), i); } return true; case "start": - obj.start = (reader.readNumber()!); + obj.start = (r.number()!); return true; case "isanacrusis": - obj.isAnacrusis = (reader.readBoolean()!); + obj.isAnacrusis = (r.boolean()!); return true; } if (["section"].indexOf(property) >= 0) { - if (reader.currentValueType !== JsonValueType.Null) { + if (r.currentValueType !== JsonValueType.Null) { obj.section = new Section(); - SectionSerializer.fromJson(obj.section, reader); + SectionSerializer.fromJson(obj.section, r); } else { obj.section = null; @@ -136,9 +136,9 @@ export class MasterBarSerializer { return true; } if (["tempoautomation"].indexOf(property) >= 0) { - if (reader.currentValueType !== JsonValueType.Null) { + if (r.currentValueType !== JsonValueType.Null) { obj.tempoAutomation = new Automation(); - AutomationSerializer.fromJson(obj.tempoAutomation, reader); + AutomationSerializer.fromJson(obj.tempoAutomation, r); } else { obj.tempoAutomation = null; diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index a91e1193c..4e07e73d5 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -21,247 +21,247 @@ import { Duration } from "@src/model/Duration"; import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; import { DynamicValue } from "@src/model/DynamicValue"; export class NoteSerializer { - public static fromJson(obj: Note, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Note, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Note | null, writer: IJsonWriter): void { + public static toJson(obj: Note | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("id"); - writer.writeNumber(obj.id); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("accentuated"); - writer.writeEnum(obj.accentuated); - writer.writePropertyName("bendType"); - writer.writeEnum(obj.bendType); - writer.writePropertyName("bendStyle"); - writer.writeEnum(obj.bendStyle); - writer.writePropertyName("isContinuedBend"); - writer.writeBoolean(obj.isContinuedBend); - writer.writePropertyName("bendPoints"); - writer.writeStartArray(); + w.startObject(); + w.prop("id"); + w.number(obj.id); + w.prop("index"); + w.number(obj.index); + w.prop("accentuated"); + w.enum(obj.accentuated); + w.prop("bendType"); + w.enum(obj.bendType); + w.prop("bendStyle"); + w.enum(obj.bendStyle); + w.prop("isContinuedBend"); + w.boolean(obj.isContinuedBend); + w.prop("bendPoints"); + w.startArray(); for (const i of obj.bendPoints) { - BendPointSerializer.toJson(i, writer); + BendPointSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("fret"); - writer.writeNumber(obj.fret); - writer.writePropertyName("string"); - writer.writeNumber(obj.string); - writer.writePropertyName("octave"); - writer.writeNumber(obj.octave); - writer.writePropertyName("tone"); - writer.writeNumber(obj.tone); - writer.writePropertyName("percussionArticulation"); - writer.writeNumber(obj.percussionArticulation); - writer.writePropertyName("isVisible"); - writer.writeBoolean(obj.isVisible); - writer.writePropertyName("isLeftHandTapped"); - writer.writeBoolean(obj.isLeftHandTapped); - writer.writePropertyName("isHammerPullOrigin"); - writer.writeBoolean(obj.isHammerPullOrigin); - writer.writePropertyName("hammerPullOriginNoteId"); - writer.writeNumber(obj.hammerPullOriginNoteId); - writer.writePropertyName("hammerPullDestinationNoteId"); - writer.writeNumber(obj.hammerPullDestinationNoteId); - writer.writePropertyName("isSlurDestination"); - writer.writeBoolean(obj.isSlurDestination); - writer.writePropertyName("slurOriginNoteId"); - writer.writeNumber(obj.slurOriginNoteId); - writer.writePropertyName("slurDestinationNoteId"); - writer.writeNumber(obj.slurDestinationNoteId); - writer.writePropertyName("harmonicType"); - writer.writeEnum(obj.harmonicType); - writer.writePropertyName("harmonicValue"); - writer.writeNumber(obj.harmonicValue); - writer.writePropertyName("isGhost"); - writer.writeBoolean(obj.isGhost); - writer.writePropertyName("isLetRing"); - writer.writeBoolean(obj.isLetRing); - writer.writePropertyName("isPalmMute"); - writer.writeBoolean(obj.isPalmMute); - writer.writePropertyName("isDead"); - writer.writeBoolean(obj.isDead); - writer.writePropertyName("isStaccato"); - writer.writeBoolean(obj.isStaccato); - writer.writePropertyName("slideInType"); - writer.writeEnum(obj.slideInType); - writer.writePropertyName("slideOutType"); - writer.writeEnum(obj.slideOutType); - writer.writePropertyName("vibrato"); - writer.writeEnum(obj.vibrato); - writer.writePropertyName("tieOriginNoteId"); - writer.writeNumber(obj.tieOriginNoteId); - writer.writePropertyName("tieDestinationNoteId"); - writer.writeNumber(obj.tieDestinationNoteId); - writer.writePropertyName("isTieDestination"); - writer.writeBoolean(obj.isTieDestination); - writer.writePropertyName("leftHandFinger"); - writer.writeEnum(obj.leftHandFinger); - writer.writePropertyName("rightHandFinger"); - writer.writeEnum(obj.rightHandFinger); - writer.writePropertyName("isFingering"); - writer.writeBoolean(obj.isFingering); - writer.writePropertyName("trillValue"); - writer.writeNumber(obj.trillValue); - writer.writePropertyName("trillSpeed"); - writer.writeEnum(obj.trillSpeed); - writer.writePropertyName("durationPercent"); - writer.writeNumber(obj.durationPercent); - writer.writePropertyName("accidentalMode"); - writer.writeEnum(obj.accidentalMode); - writer.writePropertyName("dynamics"); - writer.writeEnum(obj.dynamics); - writer.writePropertyName("isEffectSlurOrigin"); - writer.writeBoolean(obj.isEffectSlurOrigin); - writer.writePropertyName("hasEffectSlur"); - writer.writeBoolean(obj.hasEffectSlur); - writer.writeEndObject(); + w.endArray(); + w.prop("fret"); + w.number(obj.fret); + w.prop("string"); + w.number(obj.string); + w.prop("octave"); + w.number(obj.octave); + w.prop("tone"); + w.number(obj.tone); + w.prop("percussionArticulation"); + w.number(obj.percussionArticulation); + w.prop("isVisible"); + w.boolean(obj.isVisible); + w.prop("isLeftHandTapped"); + w.boolean(obj.isLeftHandTapped); + w.prop("isHammerPullOrigin"); + w.boolean(obj.isHammerPullOrigin); + w.prop("hammerPullOriginNoteId"); + w.number(obj.hammerPullOriginNoteId); + w.prop("hammerPullDestinationNoteId"); + w.number(obj.hammerPullDestinationNoteId); + w.prop("isSlurDestination"); + w.boolean(obj.isSlurDestination); + w.prop("slurOriginNoteId"); + w.number(obj.slurOriginNoteId); + w.prop("slurDestinationNoteId"); + w.number(obj.slurDestinationNoteId); + w.prop("harmonicType"); + w.enum(obj.harmonicType); + w.prop("harmonicValue"); + w.number(obj.harmonicValue); + w.prop("isGhost"); + w.boolean(obj.isGhost); + w.prop("isLetRing"); + w.boolean(obj.isLetRing); + w.prop("isPalmMute"); + w.boolean(obj.isPalmMute); + w.prop("isDead"); + w.boolean(obj.isDead); + w.prop("isStaccato"); + w.boolean(obj.isStaccato); + w.prop("slideInType"); + w.enum(obj.slideInType); + w.prop("slideOutType"); + w.enum(obj.slideOutType); + w.prop("vibrato"); + w.enum(obj.vibrato); + w.prop("tieOriginNoteId"); + w.number(obj.tieOriginNoteId); + w.prop("tieDestinationNoteId"); + w.number(obj.tieDestinationNoteId); + w.prop("isTieDestination"); + w.boolean(obj.isTieDestination); + w.prop("leftHandFinger"); + w.enum(obj.leftHandFinger); + w.prop("rightHandFinger"); + w.enum(obj.rightHandFinger); + w.prop("isFingering"); + w.boolean(obj.isFingering); + w.prop("trillValue"); + w.number(obj.trillValue); + w.prop("trillSpeed"); + w.enum(obj.trillSpeed); + w.prop("durationPercent"); + w.number(obj.durationPercent); + w.prop("accidentalMode"); + w.enum(obj.accidentalMode); + w.prop("dynamics"); + w.enum(obj.dynamics); + w.prop("isEffectSlurOrigin"); + w.boolean(obj.isEffectSlurOrigin); + w.prop("hasEffectSlur"); + w.boolean(obj.hasEffectSlur); + w.endObject(); } - public static setProperty(obj: Note, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Note, property: string, r: IJsonReader): boolean { switch (property) { case "id": - obj.id = (reader.readNumber()!); + obj.id = (r.number()!); return true; case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "accentuated": - obj.accentuated = (reader.readEnum(AccentuationType)!); + obj.accentuated = (r.enum(AccentuationType)!); return true; case "bendtype": - obj.bendType = (reader.readEnum(BendType)!); + obj.bendType = (r.enum(BendType)!); return true; case "bendstyle": - obj.bendStyle = (reader.readEnum(BendStyle)!); + obj.bendStyle = (r.enum(BendStyle)!); return true; case "iscontinuedbend": - obj.isContinuedBend = (reader.readBoolean()!); + obj.isContinuedBend = (r.boolean()!); return true; case "bendpoints": obj.bendPoints = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new BendPoint(); - BendPointSerializer.fromJson(i, reader) + BendPointSerializer.fromJson(i, r) obj.bendPoints.push(i); } return true; case "fret": - obj.fret = (reader.readNumber()!); + obj.fret = (r.number()!); return true; case "string": - obj.string = (reader.readNumber()!); + obj.string = (r.number()!); return true; case "octave": - obj.octave = (reader.readNumber()!); + obj.octave = (r.number()!); return true; case "tone": - obj.tone = (reader.readNumber()!); + obj.tone = (r.number()!); return true; case "percussionarticulation": - obj.percussionArticulation = (reader.readNumber()!); + obj.percussionArticulation = (r.number()!); return true; case "isvisible": - obj.isVisible = (reader.readBoolean()!); + obj.isVisible = (r.boolean()!); return true; case "islefthandtapped": - obj.isLeftHandTapped = (reader.readBoolean()!); + obj.isLeftHandTapped = (r.boolean()!); return true; case "ishammerpullorigin": - obj.isHammerPullOrigin = (reader.readBoolean()!); + obj.isHammerPullOrigin = (r.boolean()!); return true; case "hammerpulloriginnoteid": - obj.hammerPullOriginNoteId = (reader.readNumber()!); + obj.hammerPullOriginNoteId = (r.number()!); return true; case "hammerpulldestinationnoteid": - obj.hammerPullDestinationNoteId = (reader.readNumber()!); + obj.hammerPullDestinationNoteId = (r.number()!); return true; case "isslurdestination": - obj.isSlurDestination = (reader.readBoolean()!); + obj.isSlurDestination = (r.boolean()!); return true; case "sluroriginnoteid": - obj.slurOriginNoteId = (reader.readNumber()!); + obj.slurOriginNoteId = (r.number()!); return true; case "slurdestinationnoteid": - obj.slurDestinationNoteId = (reader.readNumber()!); + obj.slurDestinationNoteId = (r.number()!); return true; case "harmonictype": - obj.harmonicType = (reader.readEnum(HarmonicType)!); + obj.harmonicType = (r.enum(HarmonicType)!); return true; case "harmonicvalue": - obj.harmonicValue = (reader.readNumber()!); + obj.harmonicValue = (r.number()!); return true; case "isghost": - obj.isGhost = (reader.readBoolean()!); + obj.isGhost = (r.boolean()!); return true; case "isletring": - obj.isLetRing = (reader.readBoolean()!); + obj.isLetRing = (r.boolean()!); return true; case "ispalmmute": - obj.isPalmMute = (reader.readBoolean()!); + obj.isPalmMute = (r.boolean()!); return true; case "isdead": - obj.isDead = (reader.readBoolean()!); + obj.isDead = (r.boolean()!); return true; case "isstaccato": - obj.isStaccato = (reader.readBoolean()!); + obj.isStaccato = (r.boolean()!); return true; case "slideintype": - obj.slideInType = (reader.readEnum(SlideInType)!); + obj.slideInType = (r.enum(SlideInType)!); return true; case "slideouttype": - obj.slideOutType = (reader.readEnum(SlideOutType)!); + obj.slideOutType = (r.enum(SlideOutType)!); return true; case "vibrato": - obj.vibrato = (reader.readEnum(VibratoType)!); + obj.vibrato = (r.enum(VibratoType)!); return true; case "tieoriginnoteid": - obj.tieOriginNoteId = (reader.readNumber()!); + obj.tieOriginNoteId = (r.number()!); return true; case "tiedestinationnoteid": - obj.tieDestinationNoteId = (reader.readNumber()!); + obj.tieDestinationNoteId = (r.number()!); return true; case "istiedestination": - obj.isTieDestination = (reader.readBoolean()!); + obj.isTieDestination = (r.boolean()!); return true; case "lefthandfinger": - obj.leftHandFinger = (reader.readEnum(Fingers)!); + obj.leftHandFinger = (r.enum(Fingers)!); return true; case "righthandfinger": - obj.rightHandFinger = (reader.readEnum(Fingers)!); + obj.rightHandFinger = (r.enum(Fingers)!); return true; case "isfingering": - obj.isFingering = (reader.readBoolean()!); + obj.isFingering = (r.boolean()!); return true; case "trillvalue": - obj.trillValue = (reader.readNumber()!); + obj.trillValue = (r.number()!); return true; case "trillspeed": - obj.trillSpeed = (reader.readEnum(Duration)!); + obj.trillSpeed = (r.enum(Duration)!); return true; case "durationpercent": - obj.durationPercent = (reader.readNumber()!); + obj.durationPercent = (r.number()!); return true; case "accidentalmode": - obj.accidentalMode = (reader.readEnum(NoteAccidentalMode)!); + obj.accidentalMode = (r.enum(NoteAccidentalMode)!); return true; case "dynamics": - obj.dynamics = (reader.readEnum(DynamicValue)!); + obj.dynamics = (r.enum(DynamicValue)!); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = (reader.readBoolean()!); + obj.isEffectSlurOrigin = (r.boolean()!); return true; case "haseffectslur": - obj.hasEffectSlur = (reader.readBoolean()!); + obj.hasEffectSlur = (r.boolean()!); return true; } return false; diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts index b31781a66..37413982b 100644 --- a/src/generated/model/PlaybackInformationSerializer.ts +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -8,63 +8,63 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class PlaybackInformationSerializer { - public static fromJson(obj: PlaybackInformation, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: PlaybackInformation, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: PlaybackInformation | null, writer: IJsonWriter): void { + public static toJson(obj: PlaybackInformation | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("volume"); - writer.writeNumber(obj.volume); - writer.writePropertyName("balance"); - writer.writeNumber(obj.balance); - writer.writePropertyName("port"); - writer.writeNumber(obj.port); - writer.writePropertyName("program"); - writer.writeNumber(obj.program); - writer.writePropertyName("primaryChannel"); - writer.writeNumber(obj.primaryChannel); - writer.writePropertyName("secondaryChannel"); - writer.writeNumber(obj.secondaryChannel); - writer.writePropertyName("isMute"); - writer.writeBoolean(obj.isMute); - writer.writePropertyName("isSolo"); - writer.writeBoolean(obj.isSolo); - writer.writeEndObject(); + w.startObject(); + w.prop("volume"); + w.number(obj.volume); + w.prop("balance"); + w.number(obj.balance); + w.prop("port"); + w.number(obj.port); + w.prop("program"); + w.number(obj.program); + w.prop("primaryChannel"); + w.number(obj.primaryChannel); + w.prop("secondaryChannel"); + w.number(obj.secondaryChannel); + w.prop("isMute"); + w.boolean(obj.isMute); + w.prop("isSolo"); + w.boolean(obj.isSolo); + w.endObject(); } - public static setProperty(obj: PlaybackInformation, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: PlaybackInformation, property: string, r: IJsonReader): boolean { switch (property) { case "volume": - obj.volume = (reader.readNumber()!); + obj.volume = (r.number()!); return true; case "balance": - obj.balance = (reader.readNumber()!); + obj.balance = (r.number()!); return true; case "port": - obj.port = (reader.readNumber()!); + obj.port = (r.number()!); return true; case "program": - obj.program = (reader.readNumber()!); + obj.program = (r.number()!); return true; case "primarychannel": - obj.primaryChannel = (reader.readNumber()!); + obj.primaryChannel = (r.number()!); return true; case "secondarychannel": - obj.secondaryChannel = (reader.readNumber()!); + obj.secondaryChannel = (r.number()!); return true; case "ismute": - obj.isMute = (reader.readBoolean()!); + obj.isMute = (r.boolean()!); return true; case "issolo": - obj.isSolo = (reader.readBoolean()!); + obj.isSolo = (r.boolean()!); return true; } return false; diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts index b5936c047..2ff860bba 100644 --- a/src/generated/model/RenderStylesheetSerializer.ts +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -8,28 +8,28 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class RenderStylesheetSerializer { - public static fromJson(obj: RenderStylesheet, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: RenderStylesheet, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: RenderStylesheet | null, writer: IJsonWriter): void { + public static toJson(obj: RenderStylesheet | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("hideDynamics"); - writer.writeBoolean(obj.hideDynamics); - writer.writeEndObject(); + w.startObject(); + w.prop("hideDynamics"); + w.boolean(obj.hideDynamics); + w.endObject(); } - public static setProperty(obj: RenderStylesheet, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: RenderStylesheet, property: string, r: IJsonReader): boolean { switch (property) { case "hidedynamics": - obj.hideDynamics = (reader.readBoolean()!); + obj.hideDynamics = (r.boolean()!); return true; } return false; diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index a93c0594f..cada35938 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -13,117 +13,117 @@ import { RenderStylesheetSerializer } from "@src/generated/model/RenderStyleshee import { MasterBar } from "@src/model/MasterBar"; import { Track } from "@src/model/Track"; export class ScoreSerializer { - public static fromJson(obj: Score, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Score, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Score | null, writer: IJsonWriter): void { + public static toJson(obj: Score | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("album"); - writer.writeString(obj.album); - writer.writePropertyName("artist"); - writer.writeString(obj.artist); - writer.writePropertyName("copyright"); - writer.writeString(obj.copyright); - writer.writePropertyName("instructions"); - writer.writeString(obj.instructions); - writer.writePropertyName("music"); - writer.writeString(obj.music); - writer.writePropertyName("notices"); - writer.writeString(obj.notices); - writer.writePropertyName("subTitle"); - writer.writeString(obj.subTitle); - writer.writePropertyName("title"); - writer.writeString(obj.title); - writer.writePropertyName("words"); - writer.writeString(obj.words); - writer.writePropertyName("tab"); - writer.writeString(obj.tab); - writer.writePropertyName("tempo"); - writer.writeNumber(obj.tempo); - writer.writePropertyName("tempoLabel"); - writer.writeString(obj.tempoLabel); - writer.writePropertyName("masterBars"); - writer.writeStartArray(); + w.startObject(); + w.prop("album"); + w.string(obj.album); + w.prop("artist"); + w.string(obj.artist); + w.prop("copyright"); + w.string(obj.copyright); + w.prop("instructions"); + w.string(obj.instructions); + w.prop("music"); + w.string(obj.music); + w.prop("notices"); + w.string(obj.notices); + w.prop("subTitle"); + w.string(obj.subTitle); + w.prop("title"); + w.string(obj.title); + w.prop("words"); + w.string(obj.words); + w.prop("tab"); + w.string(obj.tab); + w.prop("tempo"); + w.number(obj.tempo); + w.prop("tempoLabel"); + w.string(obj.tempoLabel); + w.prop("masterBars"); + w.startArray(); for (const i of obj.masterBars) { - MasterBarSerializer.toJson(i, writer); + MasterBarSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("tracks"); - writer.writeStartArray(); + w.endArray(); + w.prop("tracks"); + w.startArray(); for (const i of obj.tracks) { - TrackSerializer.toJson(i, writer); + TrackSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("stylesheet"); - RenderStylesheetSerializer.toJson(obj.stylesheet, writer); - writer.writeEndObject(); + w.endArray(); + w.prop("stylesheet"); + RenderStylesheetSerializer.toJson(obj.stylesheet, w); + w.endObject(); } - public static setProperty(obj: Score, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Score, property: string, r: IJsonReader): boolean { switch (property) { case "album": - obj.album = (reader.readString()!); + obj.album = (r.string()!); return true; case "artist": - obj.artist = (reader.readString()!); + obj.artist = (r.string()!); return true; case "copyright": - obj.copyright = (reader.readString()!); + obj.copyright = (r.string()!); return true; case "instructions": - obj.instructions = (reader.readString()!); + obj.instructions = (r.string()!); return true; case "music": - obj.music = (reader.readString()!); + obj.music = (r.string()!); return true; case "notices": - obj.notices = (reader.readString()!); + obj.notices = (r.string()!); return true; case "subtitle": - obj.subTitle = (reader.readString()!); + obj.subTitle = (r.string()!); return true; case "title": - obj.title = (reader.readString()!); + obj.title = (r.string()!); return true; case "words": - obj.words = (reader.readString()!); + obj.words = (r.string()!); return true; case "tab": - obj.tab = (reader.readString()!); + obj.tab = (r.string()!); return true; case "tempo": - obj.tempo = (reader.readNumber()!); + obj.tempo = (r.number()!); return true; case "tempolabel": - obj.tempoLabel = (reader.readString()!); + obj.tempoLabel = (r.string()!); return true; case "masterbars": obj.masterBars = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new MasterBar(); - MasterBarSerializer.fromJson(i, reader) + MasterBarSerializer.fromJson(i, r) obj.addMasterBar(i); } return true; case "tracks": obj.tracks = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Track(); - TrackSerializer.fromJson(i, reader) + TrackSerializer.fromJson(i, r) obj.addTrack(i); } return true; } if (["stylesheet"].indexOf(property) >= 0) { - RenderStylesheetSerializer.fromJson(obj.stylesheet, reader); + RenderStylesheetSerializer.fromJson(obj.stylesheet, r); return true; } return false; diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts index 848b03993..8c3053462 100644 --- a/src/generated/model/SectionSerializer.ts +++ b/src/generated/model/SectionSerializer.ts @@ -8,33 +8,33 @@ import { IJsonReader } from "@src/io/IJsonReader"; import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class SectionSerializer { - public static fromJson(obj: Section, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Section, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Section | null, writer: IJsonWriter): void { + public static toJson(obj: Section | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("marker"); - writer.writeString(obj.marker); - writer.writePropertyName("text"); - writer.writeString(obj.text); - writer.writeEndObject(); + w.startObject(); + w.prop("marker"); + w.string(obj.marker); + w.prop("text"); + w.string(obj.text); + w.endObject(); } - public static setProperty(obj: Section, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Section, property: string, r: IJsonReader): boolean { switch (property) { case "marker": - obj.marker = (reader.readString()!); + obj.marker = (r.string()!); return true; case "text": - obj.text = (reader.readString()!); + obj.text = (r.string()!); return true; } return false; diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 5741fc6f8..250039e4b 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -12,99 +12,99 @@ import { ChordSerializer } from "@src/generated/model/ChordSerializer"; import { Bar } from "@src/model/Bar"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { - public static fromJson(obj: Staff, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Staff, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Staff | null, writer: IJsonWriter): void { + public static toJson(obj: Staff | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("bars"); - writer.writeStartArray(); + w.startObject(); + w.prop("index"); + w.number(obj.index); + w.prop("bars"); + w.startArray(); for (const i of obj.bars) { - BarSerializer.toJson(i, writer); + BarSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("chords"); - writer.writeStartObject(); - obj.chords.forEach((v, k) => { writer.writePropertyName(k); ChordSerializer.toJson(v, writer); }); - writer.writeEndObject(); - writer.writePropertyName("capo"); - writer.writeNumber(obj.capo); - writer.writePropertyName("transpositionPitch"); - writer.writeNumber(obj.transpositionPitch); - writer.writePropertyName("displayTranspositionPitch"); - writer.writeNumber(obj.displayTranspositionPitch); - writer.writePropertyName("tuning"); - writer.writeNumberArray(obj.tuning); - writer.writePropertyName("tuningName"); - writer.writeString(obj.tuningName); - writer.writePropertyName("showTablature"); - writer.writeBoolean(obj.showTablature); - writer.writePropertyName("showStandardNotation"); - writer.writeBoolean(obj.showStandardNotation); - writer.writePropertyName("isPercussion"); - writer.writeBoolean(obj.isPercussion); - writer.writePropertyName("standardNotationLineCount"); - writer.writeNumber(obj.standardNotationLineCount); - writer.writeEndObject(); + w.endArray(); + w.prop("chords"); + w.startObject(); + obj.chords.forEach((v, k) => { w.prop(k); ChordSerializer.toJson(v, w); }); + w.endObject(); + w.prop("capo"); + w.number(obj.capo); + w.prop("transpositionPitch"); + w.number(obj.transpositionPitch); + w.prop("displayTranspositionPitch"); + w.number(obj.displayTranspositionPitch); + w.prop("tuning"); + w.numberArray(obj.tuning); + w.prop("tuningName"); + w.string(obj.tuningName); + w.prop("showTablature"); + w.boolean(obj.showTablature); + w.prop("showStandardNotation"); + w.boolean(obj.showStandardNotation); + w.prop("isPercussion"); + w.boolean(obj.isPercussion); + w.prop("standardNotationLineCount"); + w.number(obj.standardNotationLineCount); + w.endObject(); } - public static setProperty(obj: Staff, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Staff, property: string, r: IJsonReader): boolean { switch (property) { case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "bars": obj.bars = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Bar(); - BarSerializer.fromJson(i, reader) + BarSerializer.fromJson(i, r) obj.addBar(i); } return true; case "chords": obj.chords = new Map(); - while (reader.nextProperty()) { + while (r.nextProp()) { const i = new Chord(); - ChordSerializer.fromJson(i, reader); - obj.addChord(reader.readPropertyName(), i); + ChordSerializer.fromJson(i, r); + obj.addChord(r.prop(), i); } return true; case "capo": - obj.capo = (reader.readNumber()!); + obj.capo = (r.number()!); return true; case "transpositionpitch": - obj.transpositionPitch = (reader.readNumber()!); + obj.transpositionPitch = (r.number()!); return true; case "displaytranspositionpitch": - obj.displayTranspositionPitch = (reader.readNumber()!); + obj.displayTranspositionPitch = (r.number()!); return true; case "tuning": - obj.tuning = (reader.readNumberArray()!); + obj.tuning = (r.numberArray()!); return true; case "tuningname": - obj.tuningName = (reader.readString()!); + obj.tuningName = (r.string()!); return true; case "showtablature": - obj.showTablature = (reader.readBoolean()!); + obj.showTablature = (r.boolean()!); return true; case "showstandardnotation": - obj.showStandardNotation = (reader.readBoolean()!); + obj.showStandardNotation = (r.boolean()!); return true; case "ispercussion": - obj.isPercussion = (reader.readBoolean()!); + obj.isPercussion = (r.boolean()!); return true; case "standardnotationlinecount": - obj.standardNotationLineCount = (reader.readNumber()!); + obj.standardNotationLineCount = (r.number()!); return true; } return false; diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index 0e2b7ad9f..5fd67f9c8 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -14,77 +14,77 @@ import { InstrumentArticulationSerializer } from "@src/generated/model/Instrumen import { Staff } from "@src/model/Staff"; import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; export class TrackSerializer { - public static fromJson(obj: Track, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Track, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Track | null, writer: IJsonWriter): void { + public static toJson(obj: Track | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("staves"); - writer.writeStartArray(); + w.startObject(); + w.prop("index"); + w.number(obj.index); + w.prop("staves"); + w.startArray(); for (const i of obj.staves) { - StaffSerializer.toJson(i, writer); + StaffSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("playbackInfo"); - PlaybackInformationSerializer.toJson(obj.playbackInfo, writer); - writer.writePropertyName("color"); - Color.toJson(obj.color, writer); - writer.writePropertyName("name"); - writer.writeString(obj.name); - writer.writePropertyName("shortName"); - writer.writeString(obj.shortName); - writer.writePropertyName("percussionArticulations"); - writer.writeStartArray(); + w.endArray(); + w.prop("playbackInfo"); + PlaybackInformationSerializer.toJson(obj.playbackInfo, w); + w.prop("color"); + Color.toJson(obj.color, w); + w.prop("name"); + w.string(obj.name); + w.prop("shortName"); + w.string(obj.shortName); + w.prop("percussionArticulations"); + w.startArray(); for (const i of obj.percussionArticulations) { - InstrumentArticulationSerializer.toJson(i, writer); + InstrumentArticulationSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writeEndObject(); + w.endArray(); + w.endObject(); } - public static setProperty(obj: Track, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Track, property: string, r: IJsonReader): boolean { switch (property) { case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "staves": obj.staves = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Staff(); - StaffSerializer.fromJson(i, reader) + StaffSerializer.fromJson(i, r) obj.addStaff(i); } return true; case "color": - obj.color = (Color.fromJson(reader)!); + obj.color = (Color.fromJson(r)!); return true; case "name": - obj.name = (reader.readString()!); + obj.name = (r.string()!); return true; case "shortname": - obj.shortName = (reader.readString()!); + obj.shortName = (r.string()!); return true; case "percussionarticulations": obj.percussionArticulations = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new InstrumentArticulation(); - InstrumentArticulationSerializer.fromJson(i, reader) + InstrumentArticulationSerializer.fromJson(i, r) obj.percussionArticulations.push(i); } return true; } if (["playbackinfo"].indexOf(property) >= 0) { - PlaybackInformationSerializer.fromJson(obj.playbackInfo, reader); + PlaybackInformationSerializer.fromJson(obj.playbackInfo, r); return true; } return false; diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index 48114f8fd..c906c6ed8 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -10,47 +10,47 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { BeatSerializer } from "@src/generated/model/BeatSerializer"; import { Beat } from "@src/model/Beat"; export class VoiceSerializer { - public static fromJson(obj: Voice, reader: IJsonReader): void { - if (reader.currentValueType !== JsonValueType.Object) { + public static fromJson(obj: Voice, r: IJsonReader): void { + if (r.currentValueType !== JsonValueType.Object) { return; } - while (reader.nextProperty()) { - this.setProperty(obj, reader.readPropertyName().toLowerCase(), reader); + while (r.nextProp()) { + this.setProperty(obj, r.prop().toLowerCase(), r); } } - public static toJson(obj: Voice | null, writer: IJsonWriter): void { + public static toJson(obj: Voice | null, w: IJsonWriter): void { if (!obj) { - writer.writeNull(); + w.null(); return; } - writer.writeStartObject(); - writer.writePropertyName("index"); - writer.writeNumber(obj.index); - writer.writePropertyName("beats"); - writer.writeStartArray(); + w.startObject(); + w.prop("index"); + w.number(obj.index); + w.prop("beats"); + w.startArray(); for (const i of obj.beats) { - BeatSerializer.toJson(i, writer); + BeatSerializer.toJson(i, w); } - writer.writeEndArray(); - writer.writePropertyName("isEmpty"); - writer.writeBoolean(obj.isEmpty); - writer.writeEndObject(); + w.endArray(); + w.prop("isEmpty"); + w.boolean(obj.isEmpty); + w.endObject(); } - public static setProperty(obj: Voice, property: string, reader: IJsonReader): boolean { + public static setProperty(obj: Voice, property: string, r: IJsonReader): boolean { switch (property) { case "index": - obj.index = (reader.readNumber()!); + obj.index = (r.number()!); return true; case "beats": obj.beats = []; - while (reader.nextArrayItem()) { + while (r.nextItem()) { const i = new Beat(); - BeatSerializer.fromJson(i, reader) + BeatSerializer.fromJson(i, r) obj.addBeat(i); } return true; case "isempty": - obj.isEmpty = (reader.readBoolean()!); + obj.isEmpty = (r.boolean()!); return true; } return false; diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts index 9f5f5e79b..58990292a 100644 --- a/src/io/IJsonReader.ts +++ b/src/io/IJsonReader.ts @@ -10,29 +10,29 @@ export interface IJsonReader { readonly currentProperty: string; readonly currentValueType: JsonValueType; - readPropertyName(): string; - readPropertyNameAsEnum(enumType: any): T; - readPropertyNameAsNumber(): number; + prop(): string; + enumProp(enumType: any): T; + numberProp(): number; - nextProperty(): boolean; - nextArrayItem(): boolean; + nextProp(): boolean; + nextItem(): boolean; - readString(): string | null; - readEnum(enumType: any): T | null; - readNumber(): number | null; - readBoolean(): boolean | null; + string(): string | null; + enum(enumType: any): T | null; + number(): number | null; + boolean(): boolean | null; - readStringArray(): string[] | null; - readEnumArray(enumType: any): T[] | null; - readNumberArray(): number[] | null; - readBooleanArray(): boolean[] | null; + stringArray(): string[] | null; + enumArray(enumType: any): T[] | null; + numberArray(): number[] | null; + booleanArray(): boolean[] | null; - readUint8Array(): Uint8Array | null; - readUint16Array(): Uint16Array | null; - readUint32Array(): Uint32Array | null; - readInt8Array(): Int8Array | null; - readInt16Array(): Int16Array | null; - readInt32Array(): Int32Array | null; - readFloat32Array(): Float32Array | null; - readFloat64Array(): Float64Array | null; + uint8Array(): Uint8Array | null; + uint16Array(): Uint16Array | null; + uint32Array(): Uint32Array | null; + int8Array(): Int8Array | null; + int16Array(): Int16Array | null; + int32Array(): Int32Array | null; + float32Array(): Float32Array | null; + float64Array(): Float64Array | null; } \ No newline at end of file diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts index cffca92af..93609a264 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/IJsonWriter.ts @@ -1,27 +1,27 @@ export interface IJsonWriter { - writeStartObject(): void; - writeEndObject(): void; + startObject(): void; + endObject(): void; - writeStartArray(): void; - writeEndArray(): void; + startArray(): void; + endArray(): void; - writePropertyName(name: any): void; + prop(name: any): void; - writeString(value: string | null): void; - writeNumber(value: number | null): void; - writeBoolean(value: boolean | null): void; - writeEnum(value: T): void; - writeNull(): void; - writeStringArray(value: string[] | null): void; - writeNumberArray(value: number[] | null): void; - writeBooleanArray(value: boolean[] | null): void; + string(value: string | null): void; + number(value: number | null): void; + boolean(value: boolean | null): void; + enum(value: T): void; + null(): void; + stringArray(value: string[] | null): void; + numberArray(value: number[] | null): void; + booleanArray(value: boolean[] | null): void; - writeUint8Array(value: Uint8Array | null): void; - writeUint16Array(value: Uint16Array | null): void; - writeUint32Array(value: Uint32Array | null): void; - writeInt8Array(value: Int8Array | null): void; - writeInt16Array(value: Int16Array | null): void; - writeInt32Array(value: Int32Array | null): void; - writeFloat32Array(value: Float32Array | null): void; - writeFloat64Array(value: Float64Array | null): void; + uint8Array(value: Uint8Array | null): void; + uint16Array(value: Uint16Array | null): void; + uint32Array(value: Uint32Array | null): void; + int8Array(value: Int8Array | null): void; + int16Array(value: Int16Array | null): void; + int32Array(value: Int32Array | null): void; + float32Array(value: Float32Array | null): void; + float64Array(value: Float64Array | null): void; } \ No newline at end of file diff --git a/src/model/Color.ts b/src/model/Color.ts index 11589c592..e6c92a131 100644 --- a/src/model/Color.ts +++ b/src/model/Color.ts @@ -69,13 +69,13 @@ export class Color { case JsonValueType.Number: { const c = new Color(0, 0, 0, 0); - c.raw = reader.readNumber()!; + c.raw = reader.number()!; c.updateRgba(); return c; } case JsonValueType.String: { - const json = reader.readString()!; + const json = reader.string()!; if (json.startsWith('#')) { if (json.length === 4) { // #RGB @@ -143,6 +143,6 @@ export class Color { } public static toJson(obj: Color, writer: IJsonWriter): void { - writer.writeNumber(obj.raw); + writer.number(obj.raw); } } diff --git a/src/model/Font.ts b/src/model/Font.ts index 0a0ef6b20..88ba244df 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -90,16 +90,16 @@ export class Font { let family = ''; let size = 0; let style = FontStyle.Plain; - while (reader.nextProperty()) { - switch (reader.readPropertyName().toLowerCase()) { + while (reader.nextProp()) { + switch (reader.prop().toLowerCase()) { case 'family': - family = reader.readString()!; + family = reader.string()!; break; case 'size': - size = reader.readNumber()!; + size = reader.number()!; break; case 'style': - style = reader.readEnum(FontStyle)!; + style = reader.enum(FontStyle)!; break; } } @@ -107,7 +107,7 @@ export class Font { } case JsonValueType.String: if (!Environment.isRunningInWorker) { - const value = reader.readString(); + const value = reader.string(); let el: HTMLElement = document.createElement('span'); el.setAttribute('style', 'font: ' + value); let style: CSSStyleDeclaration = el.style; @@ -188,13 +188,13 @@ export class Font { } public static toJson(font: Font, writer: IJsonWriter): void { - writer.writeStartObject(); - writer.writePropertyName('family'); - writer.writeString(font.family); - writer.writePropertyName('size'); - writer.writeNumber(font.size); - writer.writePropertyName('style'); - writer.writeEnum(font.style); - writer.writeEndObject(); + writer.startObject(); + writer.prop('family'); + writer.string(font.family); + writer.prop('size'); + writer.number(font.size); + writer.prop('style'); + writer.enum(font.style); + writer.endObject(); } } From 39711661fab56f0e27a3a43161ff420030b0863f Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Mon, 21 Dec 2020 16:59:28 +0100 Subject: [PATCH 11/19] Tests working --- src.compiler/typescript/SerializerEmitter.ts | 92 ++++++-- src/DisplaySettings.ts | 2 +- src/Settings.ts | 5 +- src/generated/CoreSettingsSerializer.ts | 34 ++- src/generated/DisplaySettingsSerializer.ts | 33 ++- src/generated/ImporterSettingsSerializer.ts | 10 +- src/generated/NotationSettingsSerializer.ts | 36 ++- src/generated/PlayerSettingsSerializer.ts | 40 ++-- src/generated/RenderingResourcesSerializer.ts | 4 +- src/generated/SettingsSerializer.ts | 4 +- .../SlidePlaybackSettingsSerializer.ts | 13 +- .../VibratoPlaybackSettingsSerializer.ts | 28 +-- src/generated/model/AutomationSerializer.ts | 19 +- src/generated/model/BarSerializer.ts | 21 +- src/generated/model/BeatSerializer.ts | 128 ++++------- src/generated/model/BendPointSerializer.ts | 10 +- src/generated/model/ChordSerializer.ts | 25 +-- src/generated/model/FermataSerializer.ts | 10 +- .../model/InstrumentArticulationSerializer.ts | 25 +-- src/generated/model/MasterBarSerializer.ts | 45 ++-- src/generated/model/NoteSerializer.ts | 134 ++++-------- .../model/PlaybackInformationSerializer.ts | 28 +-- .../model/RenderStylesheetSerializer.ts | 7 +- src/generated/model/ScoreSerializer.ts | 44 ++-- src/generated/model/SectionSerializer.ts | 10 +- src/generated/model/StaffSerializer.ts | 38 ++-- src/generated/model/TrackSerializer.ts | 17 +- src/generated/model/VoiceSerializer.ts | 12 +- src/io/IJsonReader.ts | 206 ++++++++++++++++-- src/io/IJsonWriter.ts | 122 +++++++++-- src/model/Beat.ts | 2 + src/model/JsonConverter.ts | 13 +- src/model/Note.ts | 1 + src/platform/javascript/AlphaTabWebWorker.ts | 7 +- .../javascript/AlphaTabWorkerScoreRenderer.ts | 8 +- src/platform/javascript/BrowserUiFacade.ts | 9 +- .../layout/HorizontalScreenLayout.ts | 32 +-- src/rendering/layout/PageViewLayout.ts | 12 +- test/visualTests/VisualTestHelper.ts | 7 +- tsconfig.base.json | 2 +- tsconfig.build-csharp.json | 2 +- tsconfig.json | 2 +- 42 files changed, 745 insertions(+), 554 deletions(-) diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index 60e20c166..f30cc9211 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -16,7 +16,6 @@ import { isMap } from '../BuilderHelpers'; import { isEnumType } from '../BuilderHelpers'; import { isNumberType } from '../BuilderHelpers'; import { wrapToNonNull } from '../BuilderHelpers'; -import { arrayify } from 'tslint/lib/utils'; interface JsonProperty { partialNames: boolean; @@ -78,14 +77,20 @@ function generateFromJsonBody() { ts.factory.createIfStatement( ts.factory.createBinaryExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'currentValueType'), - ts.SyntaxKind.ExclamationEqualsEqualsToken, - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Object'), + ts.SyntaxKind.EqualsEqualsEqualsToken, + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Null'), ), ts.factory.createBlock([ ts.factory.createReturnStatement() ]) ), - + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startObject'), + undefined, + [] + ) + ), ts.factory.createWhileStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextProp'), @@ -116,7 +121,14 @@ function generateFromJsonBody() { ) ) ]) - ) + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endObject'), + undefined, + [] + ) + ), ])); } @@ -241,14 +253,6 @@ function generateToJsonBody( const fieldName = (prop.property.name as ts.Identifier).text; const jsonName = prop.jsonNames.filter(n => n !== '')[0]; - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), - undefined, - [ - ts.factory.createStringLiteral(jsonName) - ] - ))); - if (!jsonName) { continue; } @@ -264,10 +268,18 @@ function generateToJsonBody( undefined, [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ts.factory.createStringLiteral(jsonName), ] ))); } else if (isArray) { // NOTE: nullable Object arrays are not yet supported + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + undefined, + [ + ts.factory.createStringLiteral(jsonName) + ] + ))); const arrayItemType = unwrapArrayItemType(type.type!, typeChecker)!; @@ -308,6 +320,14 @@ function generateToJsonBody( ))); } else if (isMap(type.type)) { + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + undefined, + [ + ts.factory.createStringLiteral(jsonName) + ] + ))); + const mapType = type.type as ts.TypeReference; if (!isPrimitiveType(mapType.typeArguments![0])) { throw new Error('only Map maps are supported extend if needed!'); @@ -378,6 +398,14 @@ function generateToJsonBody( ))); } else if (isImmutable(type.type)) { + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + undefined, + [ + ts.factory.createStringLiteral(jsonName) + ] + ))); + let itemSerializer = type.type.symbol.name; importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); statements.push( @@ -393,13 +421,17 @@ function generateToJsonBody( ) ); } else { - if (!type.type.symbol) { - console.log('error'); - } + statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + undefined, + [ + ts.factory.createStringLiteral(jsonName) + ] + ))); + let itemSerializer = type.type.symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); - const writeValue: ts.Statement = ts.factory.createExpressionStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), @@ -614,6 +646,13 @@ function generateSetPropertyBody(program: ts.Program, const loopItems = [ assignField(ts.factory.createArrayLiteralExpression(undefined)), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startArray'), + undefined, + [] + ) + ), ts.factory.createWhileStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextItem'), @@ -667,7 +706,14 @@ function generateSetPropertyBody(program: ts.Program, ) ) ].filter(s => !!s) as ts.Statement[]) - ) + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endArray'), + undefined, + [] + ) + ), ]; if (type.isNullable) { @@ -736,6 +782,10 @@ function generateSetPropertyBody(program: ts.Program, typeChecker.typeToTypeNode(mapType.typeArguments![1], undefined, undefined)!, ], []))); + caseStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startObject'), + undefined, [] + ))); caseStatements.push(ts.factory.createWhileStatement( ts.factory.createCallExpression( @@ -783,6 +833,12 @@ function generateSetPropertyBody(program: ts.Program, ) ].filter(s => !!s) as ts.Statement[]) )); + + caseStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endObject'), + undefined, [] + ))); + caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isImmutable(type.type)) { let itemSerializer = type.type.symbol.name; diff --git a/src/DisplaySettings.ts b/src/DisplaySettings.ts index 9211c1ff5..2d3d8fafa 100644 --- a/src/DisplaySettings.ts +++ b/src/DisplaySettings.ts @@ -95,5 +95,5 @@ export class DisplaySettings { /** * Gets or sets the padding between the music notation and the border. */ - public padding: Float32Array | null = null; + public padding: number[] | null = null; } diff --git a/src/Settings.ts b/src/Settings.ts index 803aa480f..7df28b0cd 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -3,6 +3,8 @@ import { DisplaySettings } from '@src/DisplaySettings'; import { ImporterSettings } from '@src/ImporterSettings'; import { FingeringMode, NotationMode, NotationSettings, NotationElement } from '@src/NotationSettings'; import { PlayerSettings } from '@src/PlayerSettings'; +import { SettingsSerializer } from './generated/SettingsSerializer'; +import { JsonObjectReader } from './io/IJsonReader'; /** * This public class contains instance specific settings for alphaTab @@ -14,8 +16,7 @@ export class Settings { */ public fillFromDataAttributes(dataAttributes: Map): void { dataAttributes.forEach((v, k) => { - // TODO: replace data attribute settings - // SettingsSerializer.setProperty(this, k.toLowerCase(), v); + SettingsSerializer.setProperty(this, k.toLowerCase(), new JsonObjectReader(v)); }); } diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index f1f94e71a..bd798d080 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -10,12 +10,14 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { LogLevel } from "@src/LogLevel"; export class CoreSettingsSerializer { public static fromJson(obj: CoreSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: CoreSettings | null, w: IJsonWriter): void { if (!obj) { @@ -23,26 +25,16 @@ export class CoreSettingsSerializer { return; } w.startObject(); - w.prop("scriptFile"); - w.string(obj.scriptFile); - w.prop("fontDirectory"); - w.string(obj.fontDirectory); - w.prop("file"); - w.string(obj.file); - w.prop("tex"); - w.boolean(obj.tex); - w.prop("visibilityCheckInterval"); - w.number(obj.visibilityCheckInterval); - w.prop("enableLazyLoading"); - w.boolean(obj.enableLazyLoading); - w.prop("engine"); - w.string(obj.engine); - w.prop("logLevel"); - w.enum(obj.logLevel); - w.prop("useWorkers"); - w.boolean(obj.useWorkers); - w.prop("includeNoteBounds"); - w.boolean(obj.includeNoteBounds); + w.string(obj.scriptFile, "scriptFile"); + w.string(obj.fontDirectory, "fontDirectory"); + w.string(obj.file, "file"); + w.boolean(obj.tex, "tex"); + w.number(obj.visibilityCheckInterval, "visibilityCheckInterval"); + w.boolean(obj.enableLazyLoading, "enableLazyLoading"); + w.string(obj.engine, "engine"); + w.enum(obj.logLevel, "logLevel"); + w.boolean(obj.useWorkers, "useWorkers"); + w.boolean(obj.includeNoteBounds, "includeNoteBounds"); w.endObject(); } public static setProperty(obj: CoreSettings, property: string, r: IJsonReader): boolean { diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts index ab9beb422..d7797536e 100644 --- a/src/generated/DisplaySettingsSerializer.ts +++ b/src/generated/DisplaySettingsSerializer.ts @@ -12,12 +12,14 @@ import { LayoutMode } from "@src/DisplaySettings"; import { StaveProfile } from "@src/DisplaySettings"; export class DisplaySettingsSerializer { public static fromJson(obj: DisplaySettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: DisplaySettings | null, w: IJsonWriter): void { if (!obj) { @@ -25,26 +27,17 @@ export class DisplaySettingsSerializer { return; } w.startObject(); - w.prop("scale"); - w.number(obj.scale); - w.prop("stretchForce"); - w.number(obj.stretchForce); - w.prop("layoutMode"); - w.enum(obj.layoutMode); - w.prop("staveProfile"); - w.enum(obj.staveProfile); - w.prop("barsPerRow"); - w.number(obj.barsPerRow); - w.prop("startBar"); - w.number(obj.startBar); - w.prop("barCount"); - w.number(obj.barCount); - w.prop("barCountPerPartial"); - w.number(obj.barCountPerPartial); + w.number(obj.scale, "scale"); + w.number(obj.stretchForce, "stretchForce"); + w.enum(obj.layoutMode, "layoutMode"); + w.enum(obj.staveProfile, "staveProfile"); + w.number(obj.barsPerRow, "barsPerRow"); + w.number(obj.startBar, "startBar"); + w.number(obj.barCount, "barCount"); + w.number(obj.barCountPerPartial, "barCountPerPartial"); w.prop("resources"); RenderingResourcesSerializer.toJson(obj.resources, w); - w.prop("padding"); - w.float32Array(obj.padding); + w.numberArray(obj.padding, "padding"); w.endObject(); } public static setProperty(obj: DisplaySettings, property: string, r: IJsonReader): boolean { @@ -74,7 +67,7 @@ export class DisplaySettingsSerializer { obj.barCountPerPartial = (r.number()!); return true; case "padding": - obj.padding = r.float32Array(); + obj.padding = r.numberArray(); return true; } if (["resources"].indexOf(property) >= 0) { diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts index b8a95c259..193e3d968 100644 --- a/src/generated/ImporterSettingsSerializer.ts +++ b/src/generated/ImporterSettingsSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class ImporterSettingsSerializer { public static fromJson(obj: ImporterSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: ImporterSettings | null, w: IJsonWriter): void { if (!obj) { @@ -22,10 +24,8 @@ export class ImporterSettingsSerializer { return; } w.startObject(); - w.prop("encoding"); - w.string(obj.encoding); - w.prop("mergePartGroupsInMusicXml"); - w.boolean(obj.mergePartGroupsInMusicXml); + w.string(obj.encoding, "encoding"); + w.boolean(obj.mergePartGroupsInMusicXml, "mergePartGroupsInMusicXml"); w.endObject(); } public static setProperty(obj: ImporterSettings, property: string, r: IJsonReader): boolean { diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 2069d004f..5ae223081 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -13,12 +13,14 @@ import { NotationElement } from "@src/NotationSettings"; import { TabRhythmMode } from "@src/NotationSettings"; export class NotationSettingsSerializer { public static fromJson(obj: NotationSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: NotationSettings | null, w: IJsonWriter): void { if (!obj) { @@ -26,30 +28,20 @@ export class NotationSettingsSerializer { return; } w.startObject(); - w.prop("notationMode"); - w.enum(obj.notationMode); - w.prop("fingeringMode"); - w.enum(obj.fingeringMode); + w.enum(obj.notationMode, "notationMode"); + w.enum(obj.fingeringMode, "fingeringMode"); w.prop("elements"); w.startObject(); obj.elements.forEach((v, k) => { w.prop(k); w.boolean(v); }); w.endObject(); - w.prop("rhythmMode"); - w.enum(obj.rhythmMode); - w.prop("rhythmHeight"); - w.number(obj.rhythmHeight); - w.prop("transpositionPitches"); - w.numberArray(obj.transpositionPitches); - w.prop("displayTranspositionPitches"); - w.numberArray(obj.displayTranspositionPitches); - w.prop("smallGraceTabNotes"); - w.boolean(obj.smallGraceTabNotes); - w.prop("extendBendArrowsOnTiedNotes"); - w.boolean(obj.extendBendArrowsOnTiedNotes); - w.prop("extendLineEffectsToBeatEnd"); - w.boolean(obj.extendLineEffectsToBeatEnd); - w.prop("slurHeight"); - w.number(obj.slurHeight); + w.enum(obj.rhythmMode, "rhythmMode"); + w.number(obj.rhythmHeight, "rhythmHeight"); + w.numberArray(obj.transpositionPitches, "transpositionPitches"); + w.numberArray(obj.displayTranspositionPitches, "displayTranspositionPitches"); + w.boolean(obj.smallGraceTabNotes, "smallGraceTabNotes"); + w.boolean(obj.extendBendArrowsOnTiedNotes, "extendBendArrowsOnTiedNotes"); + w.boolean(obj.extendLineEffectsToBeatEnd, "extendLineEffectsToBeatEnd"); + w.number(obj.slurHeight, "slurHeight"); w.endObject(); } public static setProperty(obj: NotationSettings, property: string, r: IJsonReader): boolean { @@ -62,9 +54,11 @@ export class NotationSettingsSerializer { return true; case "elements": obj.elements = new Map(); + r.startObject(); while (r.nextProp()) { obj.elements.set(r.enumProp(NotationElement), (r.boolean()!)); } + r.endObject(); return true; case "rhythmmode": obj.rhythmMode = (r.enum(TabRhythmMode)!); diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index d6e48e547..71ec678fc 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -10,12 +10,14 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { public static fromJson(obj: PlayerSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: PlayerSettings | null, w: IJsonWriter): void { if (!obj) { @@ -23,30 +25,18 @@ export class PlayerSettingsSerializer { return; } w.startObject(); - w.prop("soundFont"); - w.string(obj.soundFont); - w.prop("scrollElement"); - w.string(obj.scrollElement); - w.prop("enablePlayer"); - w.boolean(obj.enablePlayer); - w.prop("enableCursor"); - w.boolean(obj.enableCursor); - w.prop("enableUserInteraction"); - w.boolean(obj.enableUserInteraction); - w.prop("scrollOffsetX"); - w.number(obj.scrollOffsetX); - w.prop("scrollOffsetY"); - w.number(obj.scrollOffsetY); - w.prop("scrollMode"); - w.enum(obj.scrollMode); - w.prop("scrollSpeed"); - w.number(obj.scrollSpeed); - w.prop("songBookBendDuration"); - w.number(obj.songBookBendDuration); - w.prop("songBookDipDuration"); - w.number(obj.songBookDipDuration); - w.prop("playTripletFeel"); - w.boolean(obj.playTripletFeel); + w.string(obj.soundFont, "soundFont"); + w.string(obj.scrollElement, "scrollElement"); + w.boolean(obj.enablePlayer, "enablePlayer"); + w.boolean(obj.enableCursor, "enableCursor"); + w.boolean(obj.enableUserInteraction, "enableUserInteraction"); + w.number(obj.scrollOffsetX, "scrollOffsetX"); + w.number(obj.scrollOffsetY, "scrollOffsetY"); + w.enum(obj.scrollMode, "scrollMode"); + w.number(obj.scrollSpeed, "scrollSpeed"); + w.number(obj.songBookBendDuration, "songBookBendDuration"); + w.number(obj.songBookDipDuration, "songBookDipDuration"); + w.boolean(obj.playTripletFeel, "playTripletFeel"); w.endObject(); } public static setProperty(obj: PlayerSettings, property: string, r: IJsonReader): boolean { diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index 634997f8c..81233633b 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -11,12 +11,14 @@ import { Font } from "@src/model/Font"; import { Color } from "@src/model/Color"; export class RenderingResourcesSerializer { public static fromJson(obj: RenderingResources, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: RenderingResources | null, w: IJsonWriter): void { if (!obj) { diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts index 123542620..97427a04f 100644 --- a/src/generated/SettingsSerializer.ts +++ b/src/generated/SettingsSerializer.ts @@ -14,12 +14,14 @@ import { ImporterSettingsSerializer } from "@src/generated/ImporterSettingsSeria import { PlayerSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; export class SettingsSerializer { public static fromJson(obj: Settings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Settings | null, w: IJsonWriter): void { if (!obj) { diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts index 74ae5ec00..c10f15ff0 100644 --- a/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class SlidePlaybackSettingsSerializer { public static fromJson(obj: SlidePlaybackSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: SlidePlaybackSettings | null, w: IJsonWriter): void { if (!obj) { @@ -22,12 +24,9 @@ export class SlidePlaybackSettingsSerializer { return; } w.startObject(); - w.prop("simpleSlidePitchOffset"); - w.number(obj.simpleSlidePitchOffset); - w.prop("simpleSlideDurationRatio"); - w.number(obj.simpleSlideDurationRatio); - w.prop("shiftSlideDurationRatio"); - w.number(obj.shiftSlideDurationRatio); + w.number(obj.simpleSlidePitchOffset, "simpleSlidePitchOffset"); + w.number(obj.simpleSlideDurationRatio, "simpleSlideDurationRatio"); + w.number(obj.shiftSlideDurationRatio, "shiftSlideDurationRatio"); w.endObject(); } public static setProperty(obj: SlidePlaybackSettings, property: string, r: IJsonReader): boolean { diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts index 8b0cf803e..c738d857a 100644 --- a/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class VibratoPlaybackSettingsSerializer { public static fromJson(obj: VibratoPlaybackSettings, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: VibratoPlaybackSettings | null, w: IJsonWriter): void { if (!obj) { @@ -22,22 +24,14 @@ export class VibratoPlaybackSettingsSerializer { return; } w.startObject(); - w.prop("noteWideLength"); - w.number(obj.noteWideLength); - w.prop("noteWideAmplitude"); - w.number(obj.noteWideAmplitude); - w.prop("noteSlightLength"); - w.number(obj.noteSlightLength); - w.prop("noteSlightAmplitude"); - w.number(obj.noteSlightAmplitude); - w.prop("beatWideLength"); - w.number(obj.beatWideLength); - w.prop("beatWideAmplitude"); - w.number(obj.beatWideAmplitude); - w.prop("beatSlightLength"); - w.number(obj.beatSlightLength); - w.prop("beatSlightAmplitude"); - w.number(obj.beatSlightAmplitude); + w.number(obj.noteWideLength, "noteWideLength"); + w.number(obj.noteWideAmplitude, "noteWideAmplitude"); + w.number(obj.noteSlightLength, "noteSlightLength"); + w.number(obj.noteSlightAmplitude, "noteSlightAmplitude"); + w.number(obj.beatWideLength, "beatWideLength"); + w.number(obj.beatWideAmplitude, "beatWideAmplitude"); + w.number(obj.beatSlightLength, "beatSlightLength"); + w.number(obj.beatSlightAmplitude, "beatSlightAmplitude"); w.endObject(); } public static setProperty(obj: VibratoPlaybackSettings, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts index 37f356a0a..d137eb664 100644 --- a/src/generated/model/AutomationSerializer.ts +++ b/src/generated/model/AutomationSerializer.ts @@ -10,12 +10,14 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { AutomationType } from "@src/model/Automation"; export class AutomationSerializer { public static fromJson(obj: Automation, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Automation | null, w: IJsonWriter): void { if (!obj) { @@ -23,16 +25,11 @@ export class AutomationSerializer { return; } w.startObject(); - w.prop("isLinear"); - w.boolean(obj.isLinear); - w.prop("type"); - w.enum(obj.type); - w.prop("value"); - w.number(obj.value); - w.prop("ratioPosition"); - w.number(obj.ratioPosition); - w.prop("text"); - w.string(obj.text); + w.boolean(obj.isLinear, "isLinear"); + w.enum(obj.type, "type"); + w.number(obj.value, "value"); + w.number(obj.ratioPosition, "ratioPosition"); + w.string(obj.text, "text"); w.endObject(); } public static setProperty(obj: Automation, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index d33e21229..ce27f9bcf 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -14,12 +14,14 @@ import { Voice } from "@src/model/Voice"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { public static fromJson(obj: Bar, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Bar | null, w: IJsonWriter): void { if (!obj) { @@ -27,22 +29,17 @@ export class BarSerializer { return; } w.startObject(); - w.prop("id"); - w.number(obj.id); - w.prop("index"); - w.number(obj.index); - w.prop("clef"); - w.enum(obj.clef); - w.prop("clefOttava"); - w.enum(obj.clefOttava); + w.number(obj.id, "id"); + w.number(obj.index, "index"); + w.enum(obj.clef, "clef"); + w.enum(obj.clefOttava, "clefOttava"); w.prop("voices"); w.startArray(); for (const i of obj.voices) { VoiceSerializer.toJson(i, w); } w.endArray(); - w.prop("simileMark"); - w.enum(obj.simileMark); + w.enum(obj.simileMark, "simileMark"); w.endObject(); } public static setProperty(obj: Bar, property: string, r: IJsonReader): boolean { @@ -61,11 +58,13 @@ export class BarSerializer { return true; case "voices": obj.voices = []; + r.startArray(); while (r.nextItem()) { const i = new Voice(); VoiceSerializer.fromJson(i, r) obj.addVoice(i); } + r.endArray(); return true; case "similemark": obj.simileMark = (r.enum(SimileMark)!); diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index f8e2d8850..ffe721989 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -27,12 +27,14 @@ import { BeamDirection } from "@src/rendering/utils/BeamDirection"; import { BeatBeamingMode } from "@src/model/Beat"; export class BeatSerializer { public static fromJson(obj: Beat, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Beat | null, w: IJsonWriter): void { if (!obj) { @@ -40,100 +42,60 @@ export class BeatSerializer { return; } w.startObject(); - w.prop("id"); - w.number(obj.id); - w.prop("index"); - w.number(obj.index); + w.number(obj.id, "id"); + w.number(obj.index, "index"); w.prop("notes"); w.startArray(); for (const i of obj.notes) { NoteSerializer.toJson(i, w); } w.endArray(); - w.prop("isEmpty"); - w.boolean(obj.isEmpty); - w.prop("whammyStyle"); - w.enum(obj.whammyStyle); - w.prop("ottava"); - w.enum(obj.ottava); - w.prop("isLegatoOrigin"); - w.boolean(obj.isLegatoOrigin); - w.prop("duration"); - w.enum(obj.duration); - w.prop("isLetRing"); - w.boolean(obj.isLetRing); - w.prop("isPalmMute"); - w.boolean(obj.isPalmMute); + w.boolean(obj.isEmpty, "isEmpty"); + w.enum(obj.whammyStyle, "whammyStyle"); + w.enum(obj.ottava, "ottava"); + w.boolean(obj.isLegatoOrigin, "isLegatoOrigin"); + w.enum(obj.duration, "duration"); w.prop("automations"); w.startArray(); for (const i of obj.automations) { AutomationSerializer.toJson(i, w); } w.endArray(); - w.prop("dots"); - w.number(obj.dots); - w.prop("fadeIn"); - w.boolean(obj.fadeIn); - w.prop("lyrics"); - w.stringArray(obj.lyrics); - w.prop("hasRasgueado"); - w.boolean(obj.hasRasgueado); - w.prop("pop"); - w.boolean(obj.pop); - w.prop("slap"); - w.boolean(obj.slap); - w.prop("tap"); - w.boolean(obj.tap); - w.prop("text"); - w.string(obj.text); - w.prop("brushType"); - w.enum(obj.brushType); - w.prop("brushDuration"); - w.number(obj.brushDuration); - w.prop("tupletDenominator"); - w.number(obj.tupletDenominator); - w.prop("tupletNumerator"); - w.number(obj.tupletNumerator); - w.prop("isContinuedWhammy"); - w.boolean(obj.isContinuedWhammy); - w.prop("whammyBarType"); - w.enum(obj.whammyBarType); + w.number(obj.dots, "dots"); + w.boolean(obj.fadeIn, "fadeIn"); + w.stringArray(obj.lyrics, "lyrics"); + w.boolean(obj.hasRasgueado, "hasRasgueado"); + w.boolean(obj.pop, "pop"); + w.boolean(obj.slap, "slap"); + w.boolean(obj.tap, "tap"); + w.string(obj.text, "text"); + w.enum(obj.brushType, "brushType"); + w.number(obj.brushDuration, "brushDuration"); + w.number(obj.tupletDenominator, "tupletDenominator"); + w.number(obj.tupletNumerator, "tupletNumerator"); + w.boolean(obj.isContinuedWhammy, "isContinuedWhammy"); + w.enum(obj.whammyBarType, "whammyBarType"); w.prop("whammyBarPoints"); w.startArray(); for (const i of obj.whammyBarPoints) { BendPointSerializer.toJson(i, w); } w.endArray(); - w.prop("vibrato"); - w.enum(obj.vibrato); - w.prop("chordId"); - w.string(obj.chordId); - w.prop("graceType"); - w.enum(obj.graceType); - w.prop("pickStroke"); - w.enum(obj.pickStroke); - w.prop("tremoloSpeed"); - w.enum(obj.tremoloSpeed); - w.prop("crescendo"); - w.enum(obj.crescendo); - w.prop("displayStart"); - w.number(obj.displayStart); - w.prop("playbackStart"); - w.number(obj.playbackStart); - w.prop("displayDuration"); - w.number(obj.displayDuration); - w.prop("playbackDuration"); - w.number(obj.playbackDuration); - w.prop("dynamics"); - w.enum(obj.dynamics); - w.prop("invertBeamDirection"); - w.boolean(obj.invertBeamDirection); - w.prop("preferredBeamDirection"); - w.enum(obj.preferredBeamDirection); - w.prop("isEffectSlurOrigin"); - w.boolean(obj.isEffectSlurOrigin); - w.prop("beamingMode"); - w.enum(obj.beamingMode); + w.enum(obj.vibrato, "vibrato"); + w.string(obj.chordId, "chordId"); + w.enum(obj.graceType, "graceType"); + w.enum(obj.pickStroke, "pickStroke"); + w.enum(obj.tremoloSpeed, "tremoloSpeed"); + w.enum(obj.crescendo, "crescendo"); + w.number(obj.displayStart, "displayStart"); + w.number(obj.playbackStart, "playbackStart"); + w.number(obj.displayDuration, "displayDuration"); + w.number(obj.playbackDuration, "playbackDuration"); + w.enum(obj.dynamics, "dynamics"); + w.boolean(obj.invertBeamDirection, "invertBeamDirection"); + w.enum(obj.preferredBeamDirection, "preferredBeamDirection"); + w.boolean(obj.isEffectSlurOrigin, "isEffectSlurOrigin"); + w.enum(obj.beamingMode, "beamingMode"); w.endObject(); } public static setProperty(obj: Beat, property: string, r: IJsonReader): boolean { @@ -146,11 +108,13 @@ export class BeatSerializer { return true; case "notes": obj.notes = []; + r.startArray(); while (r.nextItem()) { const i = new Note(); NoteSerializer.fromJson(i, r) obj.addNote(i); } + r.endArray(); return true; case "isempty": obj.isEmpty = (r.boolean()!); @@ -167,19 +131,15 @@ export class BeatSerializer { case "duration": obj.duration = (r.enum(Duration)!); return true; - case "isletring": - obj.isLetRing = (r.boolean()!); - return true; - case "ispalmmute": - obj.isPalmMute = (r.boolean()!); - return true; case "automations": obj.automations = []; + r.startArray(); while (r.nextItem()) { const i = new Automation(); AutomationSerializer.fromJson(i, r) obj.automations.push(i); } + r.endArray(); return true; case "dots": obj.dots = (r.number()!); @@ -225,11 +185,13 @@ export class BeatSerializer { return true; case "whammybarpoints": obj.whammyBarPoints = []; + r.startArray(); while (r.nextItem()) { const i = new BendPoint(); BendPointSerializer.fromJson(i, r) obj.addWhammyBarPoint(i); } + r.endArray(); return true; case "vibrato": obj.vibrato = (r.enum(VibratoType)!); diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts index fffea298c..68ff7cb24 100644 --- a/src/generated/model/BendPointSerializer.ts +++ b/src/generated/model/BendPointSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class BendPointSerializer { public static fromJson(obj: BendPoint, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: BendPoint | null, w: IJsonWriter): void { if (!obj) { @@ -22,10 +24,8 @@ export class BendPointSerializer { return; } w.startObject(); - w.prop("offset"); - w.number(obj.offset); - w.prop("value"); - w.number(obj.value); + w.number(obj.offset, "offset"); + w.number(obj.value, "value"); w.endObject(); } public static setProperty(obj: BendPoint, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts index 91db145b4..47e8ce5b5 100644 --- a/src/generated/model/ChordSerializer.ts +++ b/src/generated/model/ChordSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class ChordSerializer { public static fromJson(obj: Chord, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Chord | null, w: IJsonWriter): void { if (!obj) { @@ -22,20 +24,13 @@ export class ChordSerializer { return; } w.startObject(); - w.prop("name"); - w.string(obj.name); - w.prop("firstFret"); - w.number(obj.firstFret); - w.prop("strings"); - w.numberArray(obj.strings); - w.prop("barreFrets"); - w.numberArray(obj.barreFrets); - w.prop("showName"); - w.boolean(obj.showName); - w.prop("showDiagram"); - w.boolean(obj.showDiagram); - w.prop("showFingering"); - w.boolean(obj.showFingering); + w.string(obj.name, "name"); + w.number(obj.firstFret, "firstFret"); + w.numberArray(obj.strings, "strings"); + w.numberArray(obj.barreFrets, "barreFrets"); + w.boolean(obj.showName, "showName"); + w.boolean(obj.showDiagram, "showDiagram"); + w.boolean(obj.showFingering, "showFingering"); w.endObject(); } public static setProperty(obj: Chord, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts index 9b053bf5a..88cb1ce2e 100644 --- a/src/generated/model/FermataSerializer.ts +++ b/src/generated/model/FermataSerializer.ts @@ -10,12 +10,14 @@ import { IJsonWriter } from "@src/io/IJsonWriter"; import { FermataType } from "@src/model/Fermata"; export class FermataSerializer { public static fromJson(obj: Fermata, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Fermata | null, w: IJsonWriter): void { if (!obj) { @@ -23,10 +25,8 @@ export class FermataSerializer { return; } w.startObject(); - w.prop("type"); - w.enum(obj.type); - w.prop("length"); - w.number(obj.length); + w.enum(obj.type, "type"); + w.number(obj.length, "length"); w.endObject(); } public static setProperty(obj: Fermata, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts index de9a51c1c..34573188f 100644 --- a/src/generated/model/InstrumentArticulationSerializer.ts +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -11,12 +11,14 @@ import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; import { TextBaseline } from "@src/platform/ICanvas"; export class InstrumentArticulationSerializer { public static fromJson(obj: InstrumentArticulation, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: InstrumentArticulation | null, w: IJsonWriter): void { if (!obj) { @@ -24,20 +26,13 @@ export class InstrumentArticulationSerializer { return; } w.startObject(); - w.prop("staffLine"); - w.number(obj.staffLine); - w.prop("noteHeadDefault"); - w.enum(obj.noteHeadDefault); - w.prop("noteHeadHalf"); - w.enum(obj.noteHeadHalf); - w.prop("noteHeadWhole"); - w.enum(obj.noteHeadWhole); - w.prop("techniqueSymbol"); - w.enum(obj.techniqueSymbol); - w.prop("techniqueSymbolPlacement"); - w.enum(obj.techniqueSymbolPlacement); - w.prop("outputMidiNumber"); - w.number(obj.outputMidiNumber); + w.number(obj.staffLine, "staffLine"); + w.enum(obj.noteHeadDefault, "noteHeadDefault"); + w.enum(obj.noteHeadHalf, "noteHeadHalf"); + w.enum(obj.noteHeadWhole, "noteHeadWhole"); + w.enum(obj.techniqueSymbol, "techniqueSymbol"); + w.enum(obj.techniqueSymbolPlacement, "techniqueSymbolPlacement"); + w.number(obj.outputMidiNumber, "outputMidiNumber"); w.endObject(); } public static setProperty(obj: InstrumentArticulation, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index 80041db70..ec41b5af0 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -18,12 +18,14 @@ import { Automation } from "@src/model/Automation"; import { Fermata } from "@src/model/Fermata"; export class MasterBarSerializer { public static fromJson(obj: MasterBar, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: MasterBar | null, w: IJsonWriter): void { if (!obj) { @@ -31,28 +33,17 @@ export class MasterBarSerializer { return; } w.startObject(); - w.prop("alternateEndings"); - w.number(obj.alternateEndings); - w.prop("index"); - w.number(obj.index); - w.prop("keySignature"); - w.enum(obj.keySignature); - w.prop("keySignatureType"); - w.enum(obj.keySignatureType); - w.prop("isDoubleBar"); - w.boolean(obj.isDoubleBar); - w.prop("isRepeatStart"); - w.boolean(obj.isRepeatStart); - w.prop("repeatCount"); - w.number(obj.repeatCount); - w.prop("timeSignatureNumerator"); - w.number(obj.timeSignatureNumerator); - w.prop("timeSignatureDenominator"); - w.number(obj.timeSignatureDenominator); - w.prop("timeSignatureCommon"); - w.boolean(obj.timeSignatureCommon); - w.prop("tripletFeel"); - w.enum(obj.tripletFeel); + w.number(obj.alternateEndings, "alternateEndings"); + w.number(obj.index, "index"); + w.enum(obj.keySignature, "keySignature"); + w.enum(obj.keySignatureType, "keySignatureType"); + w.boolean(obj.isDoubleBar, "isDoubleBar"); + w.boolean(obj.isRepeatStart, "isRepeatStart"); + w.number(obj.repeatCount, "repeatCount"); + w.number(obj.timeSignatureNumerator, "timeSignatureNumerator"); + w.number(obj.timeSignatureDenominator, "timeSignatureDenominator"); + w.boolean(obj.timeSignatureCommon, "timeSignatureCommon"); + w.enum(obj.tripletFeel, "tripletFeel"); w.prop("section"); if (obj.section) { SectionSerializer.toJson(obj.section, w); @@ -69,10 +60,8 @@ export class MasterBarSerializer { w.startObject(); obj.fermata.forEach((v, k) => { w.prop(k); FermataSerializer.toJson(v, w); }); w.endObject(); - w.prop("start"); - w.number(obj.start); - w.prop("isAnacrusis"); - w.boolean(obj.isAnacrusis); + w.number(obj.start, "start"); + w.boolean(obj.isAnacrusis, "isAnacrusis"); w.endObject(); } public static setProperty(obj: MasterBar, property: string, r: IJsonReader): boolean { @@ -112,11 +101,13 @@ export class MasterBarSerializer { return true; case "fermata": obj.fermata = new Map(); + r.startObject(); while (r.nextProp()) { const i = new Fermata(); FermataSerializer.fromJson(i, r); obj.fermata.set(r.numberProp(), i); } + r.endObject(); return true; case "start": obj.start = (r.number()!); diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index 4e07e73d5..995d61e04 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -22,12 +22,14 @@ import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; import { DynamicValue } from "@src/model/DynamicValue"; export class NoteSerializer { public static fromJson(obj: Note, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Note | null, w: IJsonWriter): void { if (!obj) { @@ -35,96 +37,54 @@ export class NoteSerializer { return; } w.startObject(); - w.prop("id"); - w.number(obj.id); - w.prop("index"); - w.number(obj.index); - w.prop("accentuated"); - w.enum(obj.accentuated); - w.prop("bendType"); - w.enum(obj.bendType); - w.prop("bendStyle"); - w.enum(obj.bendStyle); - w.prop("isContinuedBend"); - w.boolean(obj.isContinuedBend); + w.number(obj.id, "id"); + w.number(obj.index, "index"); + w.enum(obj.accentuated, "accentuated"); + w.enum(obj.bendType, "bendType"); + w.enum(obj.bendStyle, "bendStyle"); + w.boolean(obj.isContinuedBend, "isContinuedBend"); w.prop("bendPoints"); w.startArray(); for (const i of obj.bendPoints) { BendPointSerializer.toJson(i, w); } w.endArray(); - w.prop("fret"); - w.number(obj.fret); - w.prop("string"); - w.number(obj.string); - w.prop("octave"); - w.number(obj.octave); - w.prop("tone"); - w.number(obj.tone); - w.prop("percussionArticulation"); - w.number(obj.percussionArticulation); - w.prop("isVisible"); - w.boolean(obj.isVisible); - w.prop("isLeftHandTapped"); - w.boolean(obj.isLeftHandTapped); - w.prop("isHammerPullOrigin"); - w.boolean(obj.isHammerPullOrigin); - w.prop("hammerPullOriginNoteId"); - w.number(obj.hammerPullOriginNoteId); - w.prop("hammerPullDestinationNoteId"); - w.number(obj.hammerPullDestinationNoteId); - w.prop("isSlurDestination"); - w.boolean(obj.isSlurDestination); - w.prop("slurOriginNoteId"); - w.number(obj.slurOriginNoteId); - w.prop("slurDestinationNoteId"); - w.number(obj.slurDestinationNoteId); - w.prop("harmonicType"); - w.enum(obj.harmonicType); - w.prop("harmonicValue"); - w.number(obj.harmonicValue); - w.prop("isGhost"); - w.boolean(obj.isGhost); - w.prop("isLetRing"); - w.boolean(obj.isLetRing); - w.prop("isPalmMute"); - w.boolean(obj.isPalmMute); - w.prop("isDead"); - w.boolean(obj.isDead); - w.prop("isStaccato"); - w.boolean(obj.isStaccato); - w.prop("slideInType"); - w.enum(obj.slideInType); - w.prop("slideOutType"); - w.enum(obj.slideOutType); - w.prop("vibrato"); - w.enum(obj.vibrato); - w.prop("tieOriginNoteId"); - w.number(obj.tieOriginNoteId); - w.prop("tieDestinationNoteId"); - w.number(obj.tieDestinationNoteId); - w.prop("isTieDestination"); - w.boolean(obj.isTieDestination); - w.prop("leftHandFinger"); - w.enum(obj.leftHandFinger); - w.prop("rightHandFinger"); - w.enum(obj.rightHandFinger); - w.prop("isFingering"); - w.boolean(obj.isFingering); - w.prop("trillValue"); - w.number(obj.trillValue); - w.prop("trillSpeed"); - w.enum(obj.trillSpeed); - w.prop("durationPercent"); - w.number(obj.durationPercent); - w.prop("accidentalMode"); - w.enum(obj.accidentalMode); - w.prop("dynamics"); - w.enum(obj.dynamics); - w.prop("isEffectSlurOrigin"); - w.boolean(obj.isEffectSlurOrigin); - w.prop("hasEffectSlur"); - w.boolean(obj.hasEffectSlur); + w.number(obj.fret, "fret"); + w.number(obj.string, "string"); + w.number(obj.octave, "octave"); + w.number(obj.tone, "tone"); + w.number(obj.percussionArticulation, "percussionArticulation"); + w.boolean(obj.isVisible, "isVisible"); + w.boolean(obj.isLeftHandTapped, "isLeftHandTapped"); + w.boolean(obj.isHammerPullOrigin, "isHammerPullOrigin"); + w.number(obj.hammerPullOriginNoteId, "hammerPullOriginNoteId"); + w.number(obj.hammerPullDestinationNoteId, "hammerPullDestinationNoteId"); + w.boolean(obj.isSlurDestination, "isSlurDestination"); + w.number(obj.slurOriginNoteId, "slurOriginNoteId"); + w.number(obj.slurDestinationNoteId, "slurDestinationNoteId"); + w.enum(obj.harmonicType, "harmonicType"); + w.number(obj.harmonicValue, "harmonicValue"); + w.boolean(obj.isGhost, "isGhost"); + w.boolean(obj.isLetRing, "isLetRing"); + w.boolean(obj.isPalmMute, "isPalmMute"); + w.boolean(obj.isDead, "isDead"); + w.boolean(obj.isStaccato, "isStaccato"); + w.enum(obj.slideInType, "slideInType"); + w.enum(obj.slideOutType, "slideOutType"); + w.enum(obj.vibrato, "vibrato"); + w.number(obj.tieOriginNoteId, "tieOriginNoteId"); + w.number(obj.tieDestinationNoteId, "tieDestinationNoteId"); + w.boolean(obj.isTieDestination, "isTieDestination"); + w.enum(obj.leftHandFinger, "leftHandFinger"); + w.enum(obj.rightHandFinger, "rightHandFinger"); + w.boolean(obj.isFingering, "isFingering"); + w.number(obj.trillValue, "trillValue"); + w.enum(obj.trillSpeed, "trillSpeed"); + w.number(obj.durationPercent, "durationPercent"); + w.enum(obj.accidentalMode, "accidentalMode"); + w.enum(obj.dynamics, "dynamics"); + w.boolean(obj.isEffectSlurOrigin, "isEffectSlurOrigin"); + w.boolean(obj.hasEffectSlur, "hasEffectSlur"); w.endObject(); } public static setProperty(obj: Note, property: string, r: IJsonReader): boolean { @@ -149,11 +109,13 @@ export class NoteSerializer { return true; case "bendpoints": obj.bendPoints = []; + r.startArray(); while (r.nextItem()) { const i = new BendPoint(); BendPointSerializer.fromJson(i, r) - obj.bendPoints.push(i); + obj.addBendPoint(i); } + r.endArray(); return true; case "fret": obj.fret = (r.number()!); diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts index 37413982b..f452e69fe 100644 --- a/src/generated/model/PlaybackInformationSerializer.ts +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class PlaybackInformationSerializer { public static fromJson(obj: PlaybackInformation, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: PlaybackInformation | null, w: IJsonWriter): void { if (!obj) { @@ -22,22 +24,14 @@ export class PlaybackInformationSerializer { return; } w.startObject(); - w.prop("volume"); - w.number(obj.volume); - w.prop("balance"); - w.number(obj.balance); - w.prop("port"); - w.number(obj.port); - w.prop("program"); - w.number(obj.program); - w.prop("primaryChannel"); - w.number(obj.primaryChannel); - w.prop("secondaryChannel"); - w.number(obj.secondaryChannel); - w.prop("isMute"); - w.boolean(obj.isMute); - w.prop("isSolo"); - w.boolean(obj.isSolo); + w.number(obj.volume, "volume"); + w.number(obj.balance, "balance"); + w.number(obj.port, "port"); + w.number(obj.program, "program"); + w.number(obj.primaryChannel, "primaryChannel"); + w.number(obj.secondaryChannel, "secondaryChannel"); + w.boolean(obj.isMute, "isMute"); + w.boolean(obj.isSolo, "isSolo"); w.endObject(); } public static setProperty(obj: PlaybackInformation, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts index 2ff860bba..548b559f4 100644 --- a/src/generated/model/RenderStylesheetSerializer.ts +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class RenderStylesheetSerializer { public static fromJson(obj: RenderStylesheet, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: RenderStylesheet | null, w: IJsonWriter): void { if (!obj) { @@ -22,8 +24,7 @@ export class RenderStylesheetSerializer { return; } w.startObject(); - w.prop("hideDynamics"); - w.boolean(obj.hideDynamics); + w.boolean(obj.hideDynamics, "hideDynamics"); w.endObject(); } public static setProperty(obj: RenderStylesheet, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index cada35938..b37611499 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -14,12 +14,14 @@ import { MasterBar } from "@src/model/MasterBar"; import { Track } from "@src/model/Track"; export class ScoreSerializer { public static fromJson(obj: Score, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Score | null, w: IJsonWriter): void { if (!obj) { @@ -27,30 +29,18 @@ export class ScoreSerializer { return; } w.startObject(); - w.prop("album"); - w.string(obj.album); - w.prop("artist"); - w.string(obj.artist); - w.prop("copyright"); - w.string(obj.copyright); - w.prop("instructions"); - w.string(obj.instructions); - w.prop("music"); - w.string(obj.music); - w.prop("notices"); - w.string(obj.notices); - w.prop("subTitle"); - w.string(obj.subTitle); - w.prop("title"); - w.string(obj.title); - w.prop("words"); - w.string(obj.words); - w.prop("tab"); - w.string(obj.tab); - w.prop("tempo"); - w.number(obj.tempo); - w.prop("tempoLabel"); - w.string(obj.tempoLabel); + w.string(obj.album, "album"); + w.string(obj.artist, "artist"); + w.string(obj.copyright, "copyright"); + w.string(obj.instructions, "instructions"); + w.string(obj.music, "music"); + w.string(obj.notices, "notices"); + w.string(obj.subTitle, "subTitle"); + w.string(obj.title, "title"); + w.string(obj.words, "words"); + w.string(obj.tab, "tab"); + w.number(obj.tempo, "tempo"); + w.string(obj.tempoLabel, "tempoLabel"); w.prop("masterBars"); w.startArray(); for (const i of obj.masterBars) { @@ -107,19 +97,23 @@ export class ScoreSerializer { return true; case "masterbars": obj.masterBars = []; + r.startArray(); while (r.nextItem()) { const i = new MasterBar(); MasterBarSerializer.fromJson(i, r) obj.addMasterBar(i); } + r.endArray(); return true; case "tracks": obj.tracks = []; + r.startArray(); while (r.nextItem()) { const i = new Track(); TrackSerializer.fromJson(i, r) obj.addTrack(i); } + r.endArray(); return true; } if (["stylesheet"].indexOf(property) >= 0) { diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts index 8c3053462..732cce82a 100644 --- a/src/generated/model/SectionSerializer.ts +++ b/src/generated/model/SectionSerializer.ts @@ -9,12 +9,14 @@ import { JsonValueType } from "@src/io/IJsonReader"; import { IJsonWriter } from "@src/io/IJsonWriter"; export class SectionSerializer { public static fromJson(obj: Section, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Section | null, w: IJsonWriter): void { if (!obj) { @@ -22,10 +24,8 @@ export class SectionSerializer { return; } w.startObject(); - w.prop("marker"); - w.string(obj.marker); - w.prop("text"); - w.string(obj.text); + w.string(obj.marker, "marker"); + w.string(obj.text, "text"); w.endObject(); } public static setProperty(obj: Section, property: string, r: IJsonReader): boolean { diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 250039e4b..53bc6acb5 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -13,12 +13,14 @@ import { Bar } from "@src/model/Bar"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { public static fromJson(obj: Staff, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Staff | null, w: IJsonWriter): void { if (!obj) { @@ -26,8 +28,7 @@ export class StaffSerializer { return; } w.startObject(); - w.prop("index"); - w.number(obj.index); + w.number(obj.index, "index"); w.prop("bars"); w.startArray(); for (const i of obj.bars) { @@ -38,24 +39,15 @@ export class StaffSerializer { w.startObject(); obj.chords.forEach((v, k) => { w.prop(k); ChordSerializer.toJson(v, w); }); w.endObject(); - w.prop("capo"); - w.number(obj.capo); - w.prop("transpositionPitch"); - w.number(obj.transpositionPitch); - w.prop("displayTranspositionPitch"); - w.number(obj.displayTranspositionPitch); - w.prop("tuning"); - w.numberArray(obj.tuning); - w.prop("tuningName"); - w.string(obj.tuningName); - w.prop("showTablature"); - w.boolean(obj.showTablature); - w.prop("showStandardNotation"); - w.boolean(obj.showStandardNotation); - w.prop("isPercussion"); - w.boolean(obj.isPercussion); - w.prop("standardNotationLineCount"); - w.number(obj.standardNotationLineCount); + w.number(obj.capo, "capo"); + w.number(obj.transpositionPitch, "transpositionPitch"); + w.number(obj.displayTranspositionPitch, "displayTranspositionPitch"); + w.numberArray(obj.tuning, "tuning"); + w.string(obj.tuningName, "tuningName"); + w.boolean(obj.showTablature, "showTablature"); + w.boolean(obj.showStandardNotation, "showStandardNotation"); + w.boolean(obj.isPercussion, "isPercussion"); + w.number(obj.standardNotationLineCount, "standardNotationLineCount"); w.endObject(); } public static setProperty(obj: Staff, property: string, r: IJsonReader): boolean { @@ -65,19 +57,23 @@ export class StaffSerializer { return true; case "bars": obj.bars = []; + r.startArray(); while (r.nextItem()) { const i = new Bar(); BarSerializer.fromJson(i, r) obj.addBar(i); } + r.endArray(); return true; case "chords": obj.chords = new Map(); + r.startObject(); while (r.nextProp()) { const i = new Chord(); ChordSerializer.fromJson(i, r); obj.addChord(r.prop(), i); } + r.endObject(); return true; case "capo": obj.capo = (r.number()!); diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index 5fd67f9c8..f5808088d 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -15,12 +15,14 @@ import { Staff } from "@src/model/Staff"; import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; export class TrackSerializer { public static fromJson(obj: Track, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Track | null, w: IJsonWriter): void { if (!obj) { @@ -28,8 +30,7 @@ export class TrackSerializer { return; } w.startObject(); - w.prop("index"); - w.number(obj.index); + w.number(obj.index, "index"); w.prop("staves"); w.startArray(); for (const i of obj.staves) { @@ -40,10 +41,8 @@ export class TrackSerializer { PlaybackInformationSerializer.toJson(obj.playbackInfo, w); w.prop("color"); Color.toJson(obj.color, w); - w.prop("name"); - w.string(obj.name); - w.prop("shortName"); - w.string(obj.shortName); + w.string(obj.name, "name"); + w.string(obj.shortName, "shortName"); w.prop("percussionArticulations"); w.startArray(); for (const i of obj.percussionArticulations) { @@ -59,11 +58,13 @@ export class TrackSerializer { return true; case "staves": obj.staves = []; + r.startArray(); while (r.nextItem()) { const i = new Staff(); StaffSerializer.fromJson(i, r) obj.addStaff(i); } + r.endArray(); return true; case "color": obj.color = (Color.fromJson(r)!); @@ -76,11 +77,13 @@ export class TrackSerializer { return true; case "percussionarticulations": obj.percussionArticulations = []; + r.startArray(); while (r.nextItem()) { const i = new InstrumentArticulation(); InstrumentArticulationSerializer.fromJson(i, r) obj.percussionArticulations.push(i); } + r.endArray(); return true; } if (["playbackinfo"].indexOf(property) >= 0) { diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index c906c6ed8..133cbe0bc 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -11,12 +11,14 @@ import { BeatSerializer } from "@src/generated/model/BeatSerializer"; import { Beat } from "@src/model/Beat"; export class VoiceSerializer { public static fromJson(obj: Voice, r: IJsonReader): void { - if (r.currentValueType !== JsonValueType.Object) { + if (r.currentValueType === JsonValueType.Null) { return; } + r.startObject(); while (r.nextProp()) { this.setProperty(obj, r.prop().toLowerCase(), r); } + r.endObject(); } public static toJson(obj: Voice | null, w: IJsonWriter): void { if (!obj) { @@ -24,16 +26,14 @@ export class VoiceSerializer { return; } w.startObject(); - w.prop("index"); - w.number(obj.index); + w.number(obj.index, "index"); w.prop("beats"); w.startArray(); for (const i of obj.beats) { BeatSerializer.toJson(i, w); } w.endArray(); - w.prop("isEmpty"); - w.boolean(obj.isEmpty); + w.boolean(obj.isEmpty, "isEmpty"); w.endObject(); } public static setProperty(obj: Voice, property: string, r: IJsonReader): boolean { @@ -43,11 +43,13 @@ export class VoiceSerializer { return true; case "beats": obj.beats = []; + r.startArray(); while (r.nextItem()) { const i = new Beat(); BeatSerializer.fromJson(i, r) obj.addBeat(i); } + r.endArray(); return true; case "isempty": obj.isEmpty = (r.boolean()!); diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts index 58990292a..2bea7de29 100644 --- a/src/io/IJsonReader.ts +++ b/src/io/IJsonReader.ts @@ -3,13 +3,19 @@ export enum JsonValueType { Number, Boolean, Null, - Object + Object, + Array } export interface IJsonReader { - readonly currentProperty: string; readonly currentValueType: JsonValueType; + startObject(): void; + endObject(): void; + + startArray(): void; + endArray(): void; + prop(): string; enumProp(enumType: any): T; numberProp(): number; @@ -23,16 +29,190 @@ export interface IJsonReader { boolean(): boolean | null; stringArray(): string[] | null; - enumArray(enumType: any): T[] | null; numberArray(): number[] | null; - booleanArray(): boolean[] | null; - - uint8Array(): Uint8Array | null; - uint16Array(): Uint16Array | null; - uint32Array(): Uint32Array | null; - int8Array(): Int8Array | null; - int16Array(): Int16Array | null; - int32Array(): Int32Array | null; - float32Array(): Float32Array | null; - float64Array(): Float64Array | null; +} + +interface ReaderStackItem { + obj: any; + currentIndex: number; + + // for object iteration + currentProp?: string; + currentValue?: any; + + currentObjectKeys: string[]; +} + +export class JsonObjectReader implements IJsonReader { + private _currentItem: ReaderStackItem | null = null; + private _readStack: ReaderStackItem[] = []; + + public currentValueType: JsonValueType = JsonValueType.Null; + + public constructor(root: any) { + root = { + root: root + }; + this.setCurrentObject(root); + this.nextProp(); + } + + private updateCurrentValueType(val: any) { + switch (typeof val) { + case 'undefined': + this.currentValueType = JsonValueType.Null; + break; + case 'string': + this.currentValueType = JsonValueType.String; + break; + case 'object': + if (val === null) { + this.currentValueType = JsonValueType.Null; + } else if (Array.isArray(val)) { + this.currentValueType = JsonValueType.Array; + } else { + this.currentValueType = JsonValueType.Object; + } + break; + case 'number': + this.currentValueType = JsonValueType.Number; + break; + case 'boolean': + this.currentValueType = JsonValueType.Boolean; + break; + } + } + + private setCurrentObject(current: any) { + let currentObjectKeys: string[] = typeof current === 'object' && current !== null + ? Object.keys(current) + : []; + const obj = { + obj: current, + currentIndex: -1, + currentObjectKeys: currentObjectKeys + }; + this._readStack.push(obj); + this._currentItem = obj; + } + + public prop(): string { + return this._currentItem?.currentProp ?? ""; + } + + private parseEnum(value: string, enumType: any): T { + return enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] as any; + } + + public enumProp(enumType: any): T { + const prop = this.prop(); + const num = parseInt(prop); + return isNaN(num) + ? this.parseEnum(prop, enumType) + : num as any; + } + + public numberProp(): number { + const prop = this.prop(); + return parseInt(prop); + } + + public nextProp(): boolean { + const currentItem = this._currentItem!; + currentItem.currentIndex++; + if (currentItem.currentIndex < currentItem.currentObjectKeys.length) { + currentItem.currentProp = currentItem.currentObjectKeys[currentItem.currentIndex]; + currentItem.currentValue = currentItem.obj[currentItem.currentProp]; + this.updateCurrentValueType(currentItem.currentValue); + return true; + } else { + this.currentValueType = JsonValueType.Null; + return false; + } + } + + public nextItem(): boolean { + const currentItem = this._currentItem!; + currentItem.currentIndex++; + + if (Array.isArray(currentItem.obj) && + currentItem.currentIndex < currentItem.obj.length) { + currentItem.currentValue = currentItem.obj[currentItem.currentIndex]; + this.updateCurrentValueType(currentItem.currentValue); + return true; + } else { + return false; + } + } + + + public startObject(): void { + const currentItem = this._currentItem; + if (currentItem) { + switch (this.currentValueType) { + case JsonValueType.Object: + this.setCurrentObject(currentItem.currentValue!); + break; + case JsonValueType.Array: + this.setCurrentObject(currentItem.currentValue!); + break; + default: + throw new Error(`Cannot start object/array in the current item. item is a ${JsonValueType[this.currentValueType]}`); + } + } + } + + public endObject(): void { + this._readStack.pop(); + this._currentItem = this._readStack[this._readStack.length - 1]; + } + + public startArray(): void { + this.startObject(); + } + + public endArray(): void { + this.endObject(); + } + + public string(): string | null { + return this.value(JsonValueType.String); + } + + public enum(enumType: any): T | null { + const currentItem = this._currentItem; + if (currentItem) { + switch (this.currentValueType) { + case JsonValueType.String: + return this.parseEnum(currentItem.currentValue as string, enumType); + case JsonValueType.Number: + return currentItem.currentValue as any; + } + } + return null; + } + + public number(): number | null { + return this.value(JsonValueType.Number); + } + + public boolean(): boolean | null { + return this.value(JsonValueType.Boolean); + } + + public stringArray(): string[] | null { + return this.value(JsonValueType.Array); + } + + public numberArray(): number[] | null { + return this.value(JsonValueType.Array); + } + + private value(type: JsonValueType): T | null { + const currentItem = this._currentItem; + if (currentItem && this.currentValueType === type) { + return currentItem.currentValue as T; + } + return null; + } } \ No newline at end of file diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts index 93609a264..763241987 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/IJsonWriter.ts @@ -1,4 +1,6 @@ export interface IJsonWriter { + readonly result: unknown; + startObject(): void; endObject(): void; @@ -7,21 +9,107 @@ export interface IJsonWriter { prop(name: any): void; - string(value: string | null): void; - number(value: number | null): void; - boolean(value: boolean | null): void; - enum(value: T): void; - null(): void; - stringArray(value: string[] | null): void; - numberArray(value: number[] | null): void; - booleanArray(value: boolean[] | null): void; - - uint8Array(value: Uint8Array | null): void; - uint16Array(value: Uint16Array | null): void; - uint32Array(value: Uint32Array | null): void; - int8Array(value: Int8Array | null): void; - int16Array(value: Int16Array | null): void; - int32Array(value: Int32Array | null): void; - float32Array(value: Float32Array | null): void; - float64Array(value: Float64Array | null): void; + string(value: string | null, propName?: any): void; + number(value: number | null, propName?: any): void; + boolean(value: boolean | null, propName?: any): void; + enum(value: T, propName?: any): void; + null(propName?: any): void; + stringArray(value: string[] | null, propName?: any): void; + numberArray(value: number[] | null, propName?: any): void; +} + +export class JsonObjectWriter implements IJsonWriter { + private _objectStack: any[] = []; + private _currentPropertyName: string = ''; + + public result: unknown = null; + + public startObject(): void { + if (this._objectStack.length > 0) { + const newObject: any = {}; + const currentObject = this._objectStack[this._objectStack.length - 1]; + this._objectStack.push(newObject); + + if (Array.isArray(currentObject)) { + currentObject.push(newObject); + } else { + currentObject[this._currentPropertyName] = newObject; + } + } else { + this.result = {}; + this._objectStack.push(this.result); + } + } + + public endObject(): void { + this._objectStack.pop(); + } + + public startArray(): void { + if (this._objectStack.length > 0) { + const newObject: any = []; + const currentObject = this._objectStack[this._objectStack.length - 1]; + this._objectStack.push(newObject); + + if (Array.isArray(currentObject)) { + currentObject.push(newObject); + } else { + currentObject[this._currentPropertyName] = newObject; + } + } else { + this.result = []; + this._objectStack.push(this.result); + } + } + + public endArray(): void { + this._objectStack.pop(); + } + + public prop(name: any): void { + this._currentPropertyName = name; + } + + public string(value: string | null, propName?: any): void { + this.writeValue(value, propName); + } + + public number(value: number | null, propName?: any): void { + this.writeValue(value, propName); + } + + public boolean(value: boolean | null, propName?: any): void { + this.writeValue(value, propName); + } + + public enum(value: T, propName?: any): void { + this.writeValue(value, propName); + } + + public null(propName?: any): void { + this.writeValue(null, propName); + } + + public stringArray(value: string[] | null, propName?: any): void { + this.writeValue(value, propName); + } + + public numberArray(value: number[] | null, propName?: any): void { + this.writeValue(value, propName); + } + + private writeValue(value: any, propName?: any) { + if (this._objectStack.length > 0) { + const currentObject = this._objectStack[this._objectStack.length - 1]; + if (Array.isArray(currentObject)) { + this._objectStack.push(value); + } else if (typeof propName !== 'undefined') { + currentObject[propName] = value; + } else { + currentObject[this._currentPropertyName] = value; + } + } else { + this.result = value; + } + } } \ No newline at end of file diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 4ead01f3d..5b2104a7d 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -175,11 +175,13 @@ export class Beat { /** * Gets or sets whether any note in this beat has a let-ring applied. + * @json_ignore */ public isLetRing: boolean = false; /** * Gets or sets whether any note in this beat has a palm-mute paplied. + * @json_ignore */ public isPalmMute: boolean = false; diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 73823552e..2fba26e61 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -7,7 +7,8 @@ import { Score } from '@src/model/Score'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; import { ScoreSerializer } from '@src/generated/model/ScoreSerializer'; -import { IJsonReader } from '@src/io/IJsonReader'; +import { JsonObjectReader } from '@src/io/IJsonReader'; +import { JsonObjectWriter } from '@src/io/IJsonWriter'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further @@ -37,8 +38,9 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - // TODO: create writer - return ScoreSerializer.toJson(score, null!); + const writer = new JsonObjectWriter(); + ScoreSerializer.toJson(score, writer); + return writer.result; } /** @@ -48,7 +50,7 @@ export class JsonConverter { * @returns The converted score object. */ public static jsonToScore(json: string, settings?: Settings): Score { - return JsonConverter.jsObjectToScore(settings); + return JsonConverter.jsObjectToScore(json, settings); } /** @@ -58,9 +60,8 @@ export class JsonConverter { * @returns The converted score object. */ public static jsObjectToScore(jsObject: any, settings?: Settings): Score { - // TODO: create reader let score: Score = new Score(); - ScoreSerializer.fromJson(score, jsObject as IJsonReader); + ScoreSerializer.fromJson(score, new JsonObjectReader(jsObject)); score.finish(settings ?? new Settings()); return score; } diff --git a/src/model/Note.ts b/src/model/Note.ts index 6b82dcc50..5121091cf 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -71,6 +71,7 @@ export class Note { /** * Gets or sets a list of the points defining the bend behavior. * @clone_add addBendPoint + * @json_add addBendPoint */ public bendPoints: BendPoint[] = []; diff --git a/src/platform/javascript/AlphaTabWebWorker.ts b/src/platform/javascript/AlphaTabWebWorker.ts index ecc4e1ad1..3dfb294d1 100644 --- a/src/platform/javascript/AlphaTabWebWorker.ts +++ b/src/platform/javascript/AlphaTabWebWorker.ts @@ -6,8 +6,8 @@ import { ScoreRenderer } from '@src/rendering/ScoreRenderer'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { Environment } from '@src/Environment'; +import { JsonObjectReader } from '@src/io/IJsonReader'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; -import { IJsonReader } from '@src/io/IJsonReader'; /** * @target web @@ -31,8 +31,7 @@ export class AlphaTabWebWorker { switch (cmd) { case 'alphaTab.initialize': let settings: Settings = new Settings(); - // TODO: create json reader - SettingsSerializer.fromJson(settings, data.settings as IJsonReader); + SettingsSerializer.fromJson(settings, new JsonObjectReader(data.settings)); Logger.logLevel = settings.core.logLevel; this._renderer = new ScoreRenderer(settings); this._renderer.partialRenderFinished.on(result => { @@ -93,7 +92,7 @@ export class AlphaTabWebWorker { } private updateSettings(json: unknown): void { - SettingsSerializer.fromJson(this._renderer.settings, json as IJsonReader); + SettingsSerializer.fromJson(this._renderer.settings, new JsonObjectReader(json)); } private renderMultiple(score: Score, trackIndexes: number[]): void { diff --git a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts index 54e8c78b9..71060f048 100644 --- a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts +++ b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts @@ -8,6 +8,7 @@ import { RenderFinishedEventArgs } from '@src/rendering/RenderFinishedEventArgs' import { BoundsLookup } from '@src/rendering/utils/BoundsLookup'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; +import { JsonObjectWriter } from '@src/io/IJsonWriter'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** @@ -23,7 +24,7 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { public constructor(api: AlphaTabApiBase, settings: Settings) { this._api = api; - if(!settings.core.scriptFile) { + if (!settings.core.scriptFile) { Logger.error('Rendering', `Could not detect alphaTab script file, cannot initialize renderer`); return; } @@ -60,9 +61,10 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { } private serializeSettingsForWorker(settings: Settings): unknown { - // TODO: create Web variant of JSON writer - let json: any = SettingsSerializer.toJson(settings, null!); + const writer = new JsonObjectWriter(); + SettingsSerializer.toJson(settings, writer); // cut out player settings, they are only needed on UI thread side + const json: any = writer.result; json.player = null; return json; } diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index b6451e571..ec906afa5 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -23,8 +23,8 @@ import { AlphaTabApi } from '@src/platform/javascript/AlphaTabApi'; import { AlphaTabWorkerScoreRenderer } from '@src/platform/javascript/AlphaTabWorkerScoreRenderer'; import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; import { Cursors } from '@src/platform/Cursors'; +import { JsonObjectReader } from '@src/io/IJsonReader'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; -import { IJsonReader } from '@src/io/IJsonReader'; /** * @target web @@ -124,10 +124,9 @@ export class BrowserUiFacade implements IUiFacade { settings = raw; } else { settings = new Settings(); - // TODO: implement web variant of JSON reader - SettingsSerializer.fromJson(settings, raw as IJsonReader); + SettingsSerializer.fromJson(settings, new JsonObjectReader(raw)); } - + let dataAttributes: Map = this.getDataAttributes(); settings.fillFromDataAttributes(dataAttributes); if (settings.notation.notationMode === NotationMode.SongBook) { @@ -139,7 +138,7 @@ export class BrowserUiFacade implements IUiFacade { api.container.resize.on(this.showSvgsInViewPort.bind(this)); } this.setupFontCheckers(settings); - + this._initialTrackIndexes = this.parseTracks(settings.core.tracks); this._contents = ''; let element: HtmlElementContainer = api.container as HtmlElementContainer; diff --git a/src/rendering/layout/HorizontalScreenLayout.ts b/src/rendering/layout/HorizontalScreenLayout.ts index 37504e592..a3ebaea45 100644 --- a/src/rendering/layout/HorizontalScreenLayout.ts +++ b/src/rendering/layout/HorizontalScreenLayout.ts @@ -17,10 +17,10 @@ export class HorizontalScreenLayoutPartialInfo { * This layout arranges the bars all horizontally */ export class HorizontalScreenLayout extends ScoreLayout { - public static PagePadding: Float32Array = new Float32Array([20, 20, 20, 20]); + public static PagePadding: number[] = [20, 20, 20, 20]; public static readonly GroupSpacing: number = 20; private _group: StaveGroup | null = null; - private _pagePadding: Float32Array | null = null; + private _pagePadding: number[] | null = null; public get name(): string { return 'HorizontalScreen'; @@ -34,7 +34,7 @@ export class HorizontalScreenLayout extends ScoreLayout { return false; } - public resize(): void {} + public resize(): void { } protected doLayoutAndRender(): void { this._pagePadding = this.renderer.settings.display.padding; @@ -42,19 +42,19 @@ export class HorizontalScreenLayout extends ScoreLayout { this._pagePadding = HorizontalScreenLayout.PagePadding; } if (this._pagePadding.length === 1) { - this._pagePadding = new Float32Array([ + this._pagePadding = [ this._pagePadding[0], this._pagePadding[0], this._pagePadding[0], this._pagePadding[0] - ]); + ]; } else if (this._pagePadding.length === 2) { - this._pagePadding = new Float32Array([ + this._pagePadding = [ this._pagePadding[0], this._pagePadding[1], this._pagePadding[0], this._pagePadding[1] - ]); + ]; } let score: Score = this.renderer.score!; let canvas: ICanvas = this.renderer.canvas!; @@ -98,9 +98,9 @@ export class HorizontalScreenLayout extends ScoreLayout { Logger.debug( this.name, 'Finished partial from bar ' + - currentPartial.masterBars[0].index + - ' to ' + - currentPartial.masterBars[currentPartial.masterBars.length - 1].index, + currentPartial.masterBars[0].index + + ' to ' + + currentPartial.masterBars[currentPartial.masterBars.length - 1].index, null ); currentPartial = new HorizontalScreenLayoutPartialInfo(); @@ -118,9 +118,9 @@ export class HorizontalScreenLayout extends ScoreLayout { Logger.debug( this.name, 'Finished partial from bar ' + - currentPartial.masterBars[0].index + - ' to ' + - currentPartial.masterBars[currentPartial.masterBars.length - 1].index, + currentPartial.masterBars[0].index + + ' to ' + + currentPartial.masterBars[currentPartial.masterBars.length - 1].index, null ); } @@ -140,9 +140,9 @@ export class HorizontalScreenLayout extends ScoreLayout { Logger.debug( this.name, 'Rendering partial from bar ' + - partial.masterBars[0].index + - ' to ' + - partial.masterBars[partial.masterBars.length - 1].index, + partial.masterBars[0].index + + ' to ' + + partial.masterBars[partial.masterBars.length - 1].index, null ); this._group.paintPartial( diff --git a/src/rendering/layout/PageViewLayout.ts b/src/rendering/layout/PageViewLayout.ts index 02aadb52f..ccd6ccd97 100644 --- a/src/rendering/layout/PageViewLayout.ts +++ b/src/rendering/layout/PageViewLayout.ts @@ -14,12 +14,12 @@ import { NotationElement } from '@src/NotationSettings'; * This layout arranges the bars into a fixed width and dynamic height region. */ export class PageViewLayout extends ScoreLayout { - public static PagePadding: Float32Array = new Float32Array([40, 40, 40, 40]); + public static PagePadding: number[] = [40, 40, 40, 40]; public static readonly GroupSpacing: number = 20; private _groups: StaveGroup[] = []; private _allMasterBarRenderers: MasterBarsRenderers[] = []; private _barsFromPreviousGroup: MasterBarsRenderers[] = []; - private _pagePadding: Float32Array | null = null; + private _pagePadding: number[] | null = null; public get name(): string { return 'PageView'; @@ -35,19 +35,19 @@ export class PageViewLayout extends ScoreLayout { this._pagePadding = PageViewLayout.PagePadding; } if (this._pagePadding.length === 1) { - this._pagePadding = new Float32Array([ + this._pagePadding = [ this._pagePadding[0], this._pagePadding[0], this._pagePadding[0], this._pagePadding[0] - ]); + ]; } else if (this._pagePadding.length === 2) { - this._pagePadding = new Float32Array([ + this._pagePadding = [ this._pagePadding[0], this._pagePadding[1], this._pagePadding[0], this._pagePadding[1] - ]); + ]; } let x: number = this._pagePadding[0]; let y: number = this._pagePadding[1]; diff --git a/test/visualTests/VisualTestHelper.ts b/test/visualTests/VisualTestHelper.ts index 8a18ad725..f94856b50 100644 --- a/test/visualTests/VisualTestHelper.ts +++ b/test/visualTests/VisualTestHelper.ts @@ -9,6 +9,7 @@ import { RenderFinishedEventArgs } from '@src/rendering/RenderFinishedEventArgs' import { AlphaTexImporter } from '@src/importer/AlphaTexImporter'; import { ByteBuffer } from '@src/io/ByteBuffer'; import { PixelMatch } from './PixelMatch'; +import { JsonConverter } from '@src/model/JsonConverter'; /** * @partial @@ -127,7 +128,11 @@ export class VisualTestHelper { api.error.on(e => { reject(`Failed to render image: ${e}`); }); - api.renderScore(score, tracks); + + // NOTE: on some platforms we serialize/deserialize the score objects + // this logic does the same just to ensure we get the right result + const renderScore = JsonConverter.jsObjectToScore(JsonConverter.scoreToJsObject(score), settings); + api.renderScore(renderScore, tracks); }); await Promise.race([ diff --git a/tsconfig.base.json b/tsconfig.base.json index 166ae76ee..ec0669491 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -26,7 +26,7 @@ "baseUrl": ".", "paths": { "@src/*": [ - "src/*", + "src/*" ] }, "typeRoots": [ diff --git a/tsconfig.build-csharp.json b/tsconfig.build-csharp.json index d8d6f5fc8..71c1ec600 100644 --- a/tsconfig.build-csharp.json +++ b/tsconfig.build-csharp.json @@ -15,7 +15,7 @@ "paths": { "@src*": [ - "src*", + "src*" ], "@test*": [ "test*" diff --git a/tsconfig.json b/tsconfig.json index c43fcf86a..46a31f0ed 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "declarationDir": "dist/types.test", "paths": { "@src*": [ - "src*", + "src*" ], "@test*": [ "test*" From 20bbf40aaa120c0a47f472de42f38a3c77b6fa68 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Tue, 22 Dec 2020 00:17:17 +0100 Subject: [PATCH 12/19] Fix Csharp build --- src.compiler/csharp/CSharpAstPrinter.ts | 77 +++-- src.compiler/csharp/CSharpAstTransformer.ts | 140 ++++++--- src.compiler/typescript/SerializerEmitter.ts | 60 ++-- src.csharp/AlphaTab.Test/Test/Globals.cs | 7 +- src.csharp/AlphaTab.Test/TestPlatform.cs | 6 +- src.csharp/AlphaTab/AlphaTab.csproj | 1 + src.csharp/AlphaTab/Core/EcmaScript/Array.cs | 10 + .../AlphaTab/Core/EcmaScript/DataView.cs | 12 +- .../AlphaTab/Core/EcmaScript/Int32Array.cs | 2 +- src.csharp/AlphaTab/Core/EcmaScript/Object.cs | 23 ++ src.csharp/AlphaTab/Core/JsonObjectReader.cs | 94 ++++++ src.csharp/AlphaTab/Core/JsonObjectWriter.cs | 74 +++++ src.csharp/AlphaTab/Core/TypeHelper.cs | 69 ++++- src/CoreSettings.ts | 1 - src/generated/CoreSettingsSerializer.ts | 16 + src/io/IJsonReader.ts | 17 +- src/io/IJsonWriter.ts | 8 + src/model/Font.ts | 287 ++++++++++++++++-- src/model/JsonConverter.ts | 9 +- src/util/JsonHelper.ts | 8 - test/model/Font.test.ts | 50 +++ 21 files changed, 824 insertions(+), 147 deletions(-) create mode 100644 src.csharp/AlphaTab/Core/EcmaScript/Array.cs create mode 100644 src.csharp/AlphaTab/Core/EcmaScript/Object.cs create mode 100644 src.csharp/AlphaTab/Core/JsonObjectReader.cs create mode 100644 src.csharp/AlphaTab/Core/JsonObjectWriter.cs delete mode 100644 src/util/JsonHelper.ts create mode 100644 test/model/Font.test.ts diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index 8b47fdecc..e0fad1b4e 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -273,12 +273,12 @@ export default class CSharpAstPrinter { defaultConstructor.parameters = constructorDeclaration.parameters; defaultConstructor.baseConstructorArguments = constructorDeclaration.parameters.map( p => - ({ - parent: defaultConstructor, - nodeType: cs.SyntaxKind.Identifier, - text: p.name, - tsNode: defaultConstructor.tsNode - } as cs.Identifier) + ({ + parent: defaultConstructor, + nodeType: cs.SyntaxKind.Identifier, + text: p.name, + tsNode: defaultConstructor.tsNode + } as cs.Identifier) ); this.writeMember(defaultConstructor); } @@ -413,7 +413,7 @@ export default class CSharpAstPrinter { this.write('where '); this.write(p.name); this.write(' : '); - this.writeType(p.constraint); + this.writeType(p.constraint, false, false, true); } }); this._indent--; @@ -555,35 +555,52 @@ export default class CSharpAstPrinter { this.writeLine(';'); } - private writeType(type: cs.TypeNode, forNew: boolean = false, asNativeArray: boolean = false) { + private writeType(type: cs.TypeNode, forNew: boolean = false, asNativeArray: boolean = false, forTypeConstraint: boolean = false) { if (!type) { console.log('ERR'); } switch (type.nodeType) { case cs.SyntaxKind.PrimitiveTypeNode: - switch ((type as cs.PrimitiveTypeNode).type) { - case cs.PrimitiveType.Bool: - this.write('bool'); - break; - case cs.PrimitiveType.Dynamic: - this.write('dynamic'); - break; - case cs.PrimitiveType.Double: - this.write('double'); - break; - case cs.PrimitiveType.Int: - this.write('int'); - break; - case cs.PrimitiveType.Object: - this.write('object'); - break; - case cs.PrimitiveType.String: - this.write('string'); - break; - case cs.PrimitiveType.Void: - this.write('void'); - break; + if (forTypeConstraint) { + switch ((type as cs.PrimitiveTypeNode).type) { + case cs.PrimitiveType.Bool: + case cs.PrimitiveType.Int: + case cs.PrimitiveType.Double: + this.write('struct'); + break; + case cs.PrimitiveType.Object: + case cs.PrimitiveType.Dynamic: + case cs.PrimitiveType.String: + case cs.PrimitiveType.Void: + this.write('class'); + break; + } + } else { + switch ((type as cs.PrimitiveTypeNode).type) { + case cs.PrimitiveType.Bool: + this.write('bool'); + break; + case cs.PrimitiveType.Dynamic: + this.write('dynamic'); + break; + case cs.PrimitiveType.Double: + this.write('double'); + break; + case cs.PrimitiveType.Int: + this.write('int'); + break; + case cs.PrimitiveType.Object: + this.write('object'); + break; + case cs.PrimitiveType.String: + this.write('string'); + break; + case cs.PrimitiveType.Void: + this.write('void'); + break; + } } + break; case cs.SyntaxKind.ArrayTypeNode: const arrayType = type as cs.ArrayTypeNode; diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index 8fa819b3b..6f4a1cdc0 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -306,10 +306,26 @@ export default class CSharpAstTransformer { private shouldSkip(node: ts.Node) { const tags = ts.getJSDocTags(node).filter(t => t.tagName.text === 'target'); - if (tags.length === 0) { - return false; + if (tags.length > 0) { + return !tags.find(t => t.comment === 'csharp'); + } + + const text = node.getSourceFile().text; + const targets = ts.getLeadingCommentRanges(text, node.getStart() - node.getLeadingTriviaWidth()) + ?.map(r => { + let comment = text.substring(r.pos, r.end).trim(); + if (comment.indexOf('/*@target') >= 0) { + return comment.substring(9, comment.length - 2).trim(); + } else { + return ''; + } + }) + .filter(t => t.length > 0); + if (targets && targets.length > 0 && !targets.find(t => t === "csharp")) { + return true; } - return !tags.find(t => t.comment === 'csharp'); + + return false; } private visitEnumDeclaration(node: ts.EnumDeclaration) { @@ -1145,9 +1161,6 @@ export default class CSharpAstTransformer { classElement: ts.MethodDeclaration ) { const signature = this._context.typeChecker.getSignatureFromDeclaration(classElement); - if (!signature) { - console.log('no signature'); - } const returnType: ts.Type | undefined = signature ? this._context.typeChecker.getReturnTypeOfSignature(signature) : undefined; @@ -1235,6 +1248,10 @@ export default class CSharpAstTransformer { } private visitStatement(parent: cs.Node, s: ts.Statement): cs.Statement | null { + if (this.shouldSkip(s)) { + return null; + } + switch (s.kind) { case ts.SyntaxKind.EmptyStatement: return this.visitEmptyStatement(parent, s as ts.EmptyStatement); @@ -1655,6 +1672,10 @@ export default class CSharpAstTransformer { } private visitCaseClause(parent: cs.SwitchStatement, s: ts.CaseClause) { + if (this.shouldSkip(s)) { + return null; + } + const caseClause = { nodeType: cs.SyntaxKind.CaseClause, parent: parent, @@ -2195,30 +2216,56 @@ export default class CSharpAstTransformer { break; } - const toInt = ((bitOp.left as cs.ParenthesizedExpression).expression = { - parent: bitOp, - nodeType: cs.SyntaxKind.CastExpression, - expression: {} as cs.Expression, - type: { - parent: null, - nodeType: cs.SyntaxKind.PrimitiveTypeNode, - type: cs.PrimitiveType.Int, + const leftType = this._context.typeChecker.getTypeAtLocation(expression.left); + const rightType = this._context.typeChecker.getTypeAtLocation(expression.right); + + const isLeftEnum = (leftType.flags & ts.TypeFlags.Enum) || (leftType.flags & ts.TypeFlags.EnumLiteral); + const isRightEnum = (rightType.flags & ts.TypeFlags.Enum) || (rightType.flags & ts.TypeFlags.EnumLiteral); + + if (!isLeftEnum || !isRightEnum) { + const toInt = ((bitOp.left as cs.ParenthesizedExpression).expression = { + parent: bitOp, + nodeType: cs.SyntaxKind.CastExpression, + expression: {} as cs.Expression, + type: { + parent: null, + nodeType: cs.SyntaxKind.PrimitiveTypeNode, + type: cs.PrimitiveType.Int, + tsNode: expression + } as cs.PrimitiveTypeNode, tsNode: expression - } as cs.PrimitiveTypeNode, - tsNode: expression - } as cs.CastExpression); - toInt.expression = this.visitExpression(assignment, expression.left)!; - if (!toInt.expression) { - return null; - } + } as cs.CastExpression); + toInt.expression = this.visitExpression(assignment, expression.left)!; + if (!toInt.expression) { + return null; + } - (bitOp.right as cs.ParenthesizedExpression).expression = this.visitExpression( - bitOp.right, - expression.right - )!; + (bitOp.right as cs.ParenthesizedExpression).expression = this.visitExpression( + bitOp.right, + expression.right + )!; - if (!(bitOp.right as cs.ParenthesizedExpression).expression) { - return null; + if (!(bitOp.right as cs.ParenthesizedExpression).expression) { + return null; + } + } else { + (bitOp.left as cs.ParenthesizedExpression).expression = this.visitExpression( + assignment, + expression.left + )!; + + if (!(bitOp.right as cs.ParenthesizedExpression).expression) { + return null; + } + + (bitOp.right as cs.ParenthesizedExpression).expression = this.visitExpression( + bitOp.right, + expression.right + )!; + + if (!(bitOp.right as cs.ParenthesizedExpression).expression) { + return null; + } } return assignment; @@ -2242,19 +2289,27 @@ export default class CSharpAstTransformer { return null; } - switch (expression.operatorToken.kind) { - case ts.SyntaxKind.AmpersandToken: - case ts.SyntaxKind.GreaterThanGreaterThanToken: - case ts.SyntaxKind.LessThanLessThanToken: - case ts.SyntaxKind.BarToken: - binaryExpression.left = this.makeInt(binaryExpression.left); - binaryExpression.right = this.makeInt(binaryExpression.right); - break; - case ts.SyntaxKind.SlashToken: - if (expression.left.kind === ts.SyntaxKind.NumericLiteral && expression.right.kind === ts.SyntaxKind.NumericLiteral) { - binaryExpression.right = this.makeDouble(binaryExpression.right); - } - break; + const leftType = this._context.typeChecker.getTypeAtLocation(expression.left); + const rightType = this._context.typeChecker.getTypeAtLocation(expression.right); + + const isLeftEnum = (leftType.flags & ts.TypeFlags.Enum) || (leftType.flags & ts.TypeFlags.EnumLiteral); + const isRightEnum = (rightType.flags & ts.TypeFlags.Enum) || (rightType.flags & ts.TypeFlags.EnumLiteral); + + if (!isLeftEnum || !isRightEnum) { + switch (expression.operatorToken.kind) { + case ts.SyntaxKind.AmpersandToken: + case ts.SyntaxKind.GreaterThanGreaterThanToken: + case ts.SyntaxKind.LessThanLessThanToken: + case ts.SyntaxKind.BarToken: + binaryExpression.left = this.makeInt(binaryExpression.left); + binaryExpression.right = this.makeInt(binaryExpression.right); + break; + case ts.SyntaxKind.SlashToken: + if (expression.left.kind === ts.SyntaxKind.NumericLiteral && expression.right.kind === ts.SyntaxKind.NumericLiteral) { + binaryExpression.right = this.makeDouble(binaryExpression.right); + } + break; + } } return binaryExpression; @@ -2803,7 +2858,7 @@ export default class CSharpAstTransformer { } let type = symbol ? this._context.typeChecker.getTypeOfSymbolAtLocation(symbol!, expression.expression) : null; - if(type) { + if (type) { type = this._context.typeChecker.getNonNullableType(type); } const isArrayAccessor = !symbol || (type && type.symbol && !!type.symbol.members?.has(ts.escapeLeadingUnderscores('slice'))); @@ -3043,8 +3098,9 @@ export default class CSharpAstTransformer { case ts.SyntaxKind.BinaryExpression: break; default: - switch(identifier.tsSymbol.flags) { + switch (identifier.tsSymbol.flags) { case ts.SymbolFlags.Alias: + case ts.SymbolFlags.RegularEnum: return { parent: parent, nodeType: cs.SyntaxKind.TypeOfExpression, diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index f30cc9211..a06cebc15 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -21,6 +21,7 @@ interface JsonProperty { partialNames: boolean; property: ts.PropertyDeclaration; jsonNames: string[]; + target?: string; } function isImmutable(type: ts.Type | null): boolean { @@ -182,6 +183,9 @@ function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeCheck const isArray = isTypedArray(type); const arrayItemType = unwrapArrayItemType(type, typeChecker); + if (hasFlag(type, ts.TypeFlags.Unknown)) { + return "unknown"; + } if (hasFlag(type, ts.TypeFlags.Number)) { return "number"; } @@ -262,8 +266,10 @@ function generateToJsonBody( let writeValueMethodName: string | null = getWriteMethodNameForPrimitive(type.type!, typeChecker); + let propertyStatements: ts.Statement[] = []; + if (writeValueMethodName) { - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), writeValueMethodName), undefined, [ @@ -273,7 +279,7 @@ function generateToJsonBody( ))); } else if (isArray) { // NOTE: nullable Object arrays are not yet supported - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ @@ -286,13 +292,13 @@ function generateToJsonBody( let itemSerializer = arrayItemType.symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startArray'), undefined, [] ))); - statements.push(ts.factory.createForOfStatement( + propertyStatements.push(ts.factory.createForOfStatement( undefined, ts.factory.createVariableDeclarationList( [ts.factory.createVariableDeclaration('i')], @@ -313,14 +319,14 @@ function generateToJsonBody( ]) )); - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endArray'), undefined, [] ))); } else if (isMap(type.type)) { - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ @@ -358,13 +364,13 @@ function generateToJsonBody( ); } - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startObject'), undefined, [] ))); - statements.push( + propertyStatements.push( ts.factory.createExpressionStatement( ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) @@ -391,14 +397,14 @@ function generateToJsonBody( ) ); - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endObject'), undefined, [] ))); } else if (isImmutable(type.type)) { - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ @@ -408,7 +414,7 @@ function generateToJsonBody( let itemSerializer = type.type.symbol.name; importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); - statements.push( + propertyStatements.push( ts.factory.createExpressionStatement( ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), @@ -421,7 +427,7 @@ function generateToJsonBody( ) ); } else { - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( + propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), undefined, [ @@ -443,7 +449,7 @@ function generateToJsonBody( )); if (type.isNullable) { - statements.push(ts.factory.createIfStatement( + propertyStatements.push(ts.factory.createIfStatement( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), ts.factory.createBlock([ writeValue @@ -455,9 +461,15 @@ function generateToJsonBody( )) )); } else { - statements.push(writeValue); + propertyStatements.push(writeValue); } } + + if (prop.target) { + propertyStatements = propertyStatements.map(s => ts.addSyntheticLeadingComment(s, ts.SyntaxKind.MultiLineCommentTrivia, `@target ${prop.target}`, true)); + } + + statements.push(...propertyStatements); } statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( @@ -524,6 +536,9 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke const isArray = isTypedArray(type); const arrayItemType = unwrapArrayItemType(type, typeChecker); + if (hasFlag(type, ts.TypeFlags.Unknown)) { + return "unknown"; + } if (hasFlag(type, ts.TypeFlags.Number)) { return "number"; } @@ -1003,13 +1018,15 @@ function generateSetPropertyBody(program: ts.Program, if (caseStatements.length > 0) { for (let i = 0; i < caseValues.length; i++) { - cases.push( - ts.factory.createCaseClause( - ts.factory.createStringLiteral(caseValues[i]), - // last case gets the statements, others are fall through - i < caseValues.length - 1 ? [] : caseStatements - ) + let caseClause = ts.factory.createCaseClause( + ts.factory.createStringLiteral(caseValues[i]), + // last case gets the statements, others are fall through + i < caseValues.length - 1 ? [] : caseStatements ); + if (prop.target && i === 0) { + caseClause = ts.addSyntheticLeadingComment(caseClause, ts.SyntaxKind.MultiLineCommentTrivia, `@target ${prop.target}`, true); + } + cases.push(caseClause); } } } @@ -1096,7 +1113,8 @@ export default createEmitter('json', (program, input) => { propertiesToSerialize.push({ property: propertyDeclaration, jsonNames: jsonNames, - partialNames: !!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_partial_names') + partialNames: !!ts.getJSDocTags(member).find(t => t.tagName.text === 'json_partial_names'), + target: ts.getJSDocTags(member).find(t => t.tagName.text === 'target')?.comment }); } } diff --git a/src.csharp/AlphaTab.Test/Test/Globals.cs b/src.csharp/AlphaTab.Test/Test/Globals.cs index 80d918836..788dc47dc 100644 --- a/src.csharp/AlphaTab.Test/Test/Globals.cs +++ b/src.csharp/AlphaTab.Test/Test/Globals.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace AlphaTab.Test { @@ -9,9 +10,9 @@ public static Expector Expect(T actual) return new Expector(actual); } - public static void Fail(string message) + public static void Fail(object message) { - Assert.Fail(message); + Assert.Fail(Convert.ToString(message)); } } diff --git a/src.csharp/AlphaTab.Test/TestPlatform.cs b/src.csharp/AlphaTab.Test/TestPlatform.cs index fe843787d..daf1d5804 100644 --- a/src.csharp/AlphaTab.Test/TestPlatform.cs +++ b/src.csharp/AlphaTab.Test/TestPlatform.cs @@ -1,4 +1,6 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Threading.Tasks; using AlphaTab.Core.EcmaScript; @@ -13,7 +15,7 @@ public static async Task LoadFile(string path) await fs.CopyToAsync(ms); return new Uint8Array(ms.ToArray()); } - + public static Task> ListDirectory(string path) { return Task.FromResult((IList)Directory.EnumerateFiles(path).ToList()); diff --git a/src.csharp/AlphaTab/AlphaTab.csproj b/src.csharp/AlphaTab/AlphaTab.csproj index 89e3e356f..879026aea 100644 --- a/src.csharp/AlphaTab/AlphaTab.csproj +++ b/src.csharp/AlphaTab/AlphaTab.csproj @@ -17,6 +17,7 @@ Generated\%(RecursiveDir)\%(Filename)%(Extension) + diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs new file mode 100644 index 000000000..6fd8f802c --- /dev/null +++ b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs @@ -0,0 +1,10 @@ +namespace AlphaTab.Core.EcmaScript +{ + internal static class Array + { + public static bool IsArray(object? o) + { + return o is System.Array; + } + } +} diff --git a/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs b/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs index 483f4f8a9..2cc87959c 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/DataView.cs @@ -16,7 +16,7 @@ public void SetUint16(double offset, double value, bool littleEndian) var bytes = BitConverter.GetBytes((ushort) value); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } Buffer.BlockCopy(bytes, 0, _buffer.Raw.Array, _buffer.Raw.Offset + (int) offset, @@ -30,7 +30,7 @@ public double GetInt16(double offset, bool littleEndian) bytes.Length); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } return BitConverter.ToInt16(bytes, 0); @@ -41,7 +41,7 @@ public void SetInt16(double offset, double value, bool littleEndian) var bytes = BitConverter.GetBytes((short) value); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } Buffer.BlockCopy(bytes, 0, _buffer.Raw.Array, _buffer.Raw.Offset + (int) offset, @@ -55,7 +55,7 @@ public double GetUint32(double offset, bool littleEndian) bytes.Length); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } return BitConverter.ToUInt32(bytes, 0); @@ -66,7 +66,7 @@ public void SetInt32(double offset, double value, bool littleEndian) var bytes = BitConverter.GetBytes((int) value); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } Buffer.BlockCopy(bytes, 0, _buffer.Raw.Array, _buffer.Raw.Offset + (int) offset, bytes @@ -80,7 +80,7 @@ public double GetUint16(double offset, bool littleEndian) bytes.Length); if (littleEndian != BitConverter.IsLittleEndian) { - Array.Reverse(bytes); + System.Array.Reverse(bytes); } return BitConverter.ToUInt16(bytes, 0); diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Int32Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Int32Array.cs index 0ee1ba2c2..993a37cb0 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Int32Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Int32Array.cs @@ -26,7 +26,7 @@ public void Fill(int i) { if (i == 0) { - Array.Clear(_data, 0, _data.Length); + System.Array.Clear(_data, 0, _data.Length); } else { diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Object.cs b/src.csharp/AlphaTab/Core/EcmaScript/Object.cs new file mode 100644 index 000000000..33ddd23f1 --- /dev/null +++ b/src.csharp/AlphaTab/Core/EcmaScript/Object.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace AlphaTab.Core.EcmaScript +{ + internal static class Object + { + public static IList Keys(object p) + { + if (p is IDictionary d) + { + return d.Keys.OfType().Select(o => o.ToString()).ToList(); + } + + return p.GetType() + .GetProperties(BindingFlags.Instance | BindingFlags.Public) + .Select(prop => prop.Name) + .ToList(); + } + } +} diff --git a/src.csharp/AlphaTab/Core/JsonObjectReader.cs b/src.csharp/AlphaTab/Core/JsonObjectReader.cs new file mode 100644 index 000000000..96f80481c --- /dev/null +++ b/src.csharp/AlphaTab/Core/JsonObjectReader.cs @@ -0,0 +1,94 @@ +using System.Collections.Generic; +using AlphaTab.Io; + +namespace AlphaTab.Core +{ + public class JsonObjectReader : IJsonReader + { + public JsonValueType CurrentValueType { get; } + + public JsonObjectReader(object? value) + { + } + + public void StartObject() + { + throw new System.NotImplementedException(); + } + + public void EndObject() + { + throw new System.NotImplementedException(); + } + + public void StartArray() + { + throw new System.NotImplementedException(); + } + + public void EndArray() + { + throw new System.NotImplementedException(); + } + + public string Prop() + { + throw new System.NotImplementedException(); + } + + public T EnumProp(object? enumType) + { + throw new System.NotImplementedException(); + } + + public double NumberProp() + { + throw new System.NotImplementedException(); + } + + public bool NextProp() + { + throw new System.NotImplementedException(); + } + + public bool NextItem() + { + throw new System.NotImplementedException(); + } + + public object? Unknown() + { + throw new System.NotImplementedException(); + } + + public string? String() + { + throw new System.NotImplementedException(); + } + + public T? Enum(dynamic enumType) where T : struct + { + throw new System.NotImplementedException(); + } + + public double? Number() + { + throw new System.NotImplementedException(); + } + + public bool? Boolean() + { + throw new System.NotImplementedException(); + } + + public IList? StringArray() + { + throw new System.NotImplementedException(); + } + + public IList? NumberArray() + { + throw new System.NotImplementedException(); + } + } +} diff --git a/src.csharp/AlphaTab/Core/JsonObjectWriter.cs b/src.csharp/AlphaTab/Core/JsonObjectWriter.cs new file mode 100644 index 000000000..4da80b618 --- /dev/null +++ b/src.csharp/AlphaTab/Core/JsonObjectWriter.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using AlphaTab.Io; + +namespace AlphaTab.Core +{ + public class JsonObjectWriter : IJsonWriter + { + public object? Result { get; } + public void StartObject() + { + throw new System.NotImplementedException(); + } + + public void EndObject() + { + throw new System.NotImplementedException(); + } + + public void StartArray() + { + throw new System.NotImplementedException(); + } + + public void EndArray() + { + throw new System.NotImplementedException(); + } + + public void Prop(dynamic name) + { + throw new System.NotImplementedException(); + } + + public void Unknown(object? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void String(string? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void Number(double? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void Boolean(bool? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void Enum(T value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void Null(dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void StringArray(IList? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + + public void NumberArray(IList? value, dynamic? propName = default) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/src.csharp/AlphaTab/Core/TypeHelper.cs b/src.csharp/AlphaTab/Core/TypeHelper.cs index 42a7fcab5..6d3e45b02 100644 --- a/src.csharp/AlphaTab/Core/TypeHelper.cs +++ b/src.csharp/AlphaTab/Core/TypeHelper.cs @@ -54,11 +54,12 @@ public static void Reverse(this IList data) } else if (data is T[] array) { - Array.Reverse(array); + System.Array.Reverse(array); } else { - throw new NotSupportedException("Cannot reverse list of type " + data.GetType().FullName); + throw new NotSupportedException("Cannot reverse list of type " + + data.GetType().FullName); } } @@ -153,17 +154,32 @@ public static void InsertRange(this IList data, int index, IEnumerable public static void Sort(this IList data, Func func) { - if (data is System.Collections.Generic.List l) - { - l.Sort((a, b) => (int) func(a, b)); - } - else if(data is T[] array) + switch (data) { - Array.Sort(array, (a, b) => (int) func(a, b)); + case System.Collections.Generic.List l: + l.Sort((a, b) => (int) func(a, b)); + break; + case T[] array: + System.Array.Sort(array, (a, b) => (int) func(a, b)); + break; + default: + throw new NotSupportedException("Cannot sort list of type " + + data.GetType().FullName); } - else + } + public static void Sort(this IList data) + { + switch (data) { - throw new NotSupportedException("Cannot sort list of type " + data.GetType().FullName); + case List l: + l.Sort(); + break; + case T[] array: + System.Array.Sort(array); + break; + default: + throw new NotSupportedException("Cannot sort list of type " + + data.GetType().FullName); } } @@ -254,9 +270,40 @@ public static bool IsTruthy(double s) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static IList Map(this IList source, Func func) + public static IList Map(this IList source, + Func func) { return source.Select(func).ToList(); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Substring(this string s, double startIndex, double length) + { + return s.Substring((int) startIndex, (int) length); + } + + public static string TypeOf(object? actual) + { + switch (actual) + { + case string _: + return "string"; + case bool _: + return "boolean"; + case byte _: + case short _: + case int _: + case long _: + case sbyte _: + case ushort _: + case uint _: + case ulong _: + case float _: + case double _: + return "number"; + default: + return "object"; + } + } } } diff --git a/src/CoreSettings.ts b/src/CoreSettings.ts index 8699de9d8..a9aa106d8 100644 --- a/src/CoreSettings.ts +++ b/src/CoreSettings.ts @@ -33,7 +33,6 @@ export class CoreSettings { /** * Gets or sets the initial tracks that should be loaded for the score. * @target web - * @json_ignore */ public tracks: unknown = null; diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index bd798d080..f8ec51e51 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -25,10 +25,17 @@ export class CoreSettingsSerializer { return; } w.startObject(); + /*@target web*/ w.string(obj.scriptFile, "scriptFile"); + /*@target web*/ w.string(obj.fontDirectory, "fontDirectory"); + /*@target web*/ w.string(obj.file, "file"); + /*@target web*/ w.boolean(obj.tex, "tex"); + /*@target web*/ + w.unknown(obj.tracks, "tracks"); + /*@target web*/ w.number(obj.visibilityCheckInterval, "visibilityCheckInterval"); w.boolean(obj.enableLazyLoading, "enableLazyLoading"); w.string(obj.engine, "engine"); @@ -39,18 +46,27 @@ export class CoreSettingsSerializer { } public static setProperty(obj: CoreSettings, property: string, r: IJsonReader): boolean { switch (property) { + /*@target web*/ case "scriptfile": obj.scriptFile = r.string(); return true; + /*@target web*/ case "fontdirectory": obj.fontDirectory = r.string(); return true; + /*@target web*/ case "file": obj.file = r.string(); return true; + /*@target web*/ case "tex": obj.tex = (r.boolean()!); return true; + /*@target web*/ + case "tracks": + obj.tracks = (r.unknown()!); + return true; + /*@target web*/ case "visibilitycheckinterval": obj.visibilityCheckInterval = (r.number()!); return true; diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts index 2bea7de29..d41b171dc 100644 --- a/src/io/IJsonReader.ts +++ b/src/io/IJsonReader.ts @@ -17,14 +17,15 @@ export interface IJsonReader { endArray(): void; prop(): string; - enumProp(enumType: any): T; + enumProp(enumType: unknown): T; numberProp(): number; nextProp(): boolean; nextItem(): boolean; + unknown(): unknown; string(): string | null; - enum(enumType: any): T | null; + enum(enumType: any): T | null; number(): number | null; boolean(): boolean | null; @@ -32,6 +33,9 @@ export interface IJsonReader { numberArray(): number[] | null; } +/** + * @target web + */ interface ReaderStackItem { obj: any; currentIndex: number; @@ -43,6 +47,9 @@ interface ReaderStackItem { currentObjectKeys: string[]; } +/** + * @target web + */ export class JsonObjectReader implements IJsonReader { private _currentItem: ReaderStackItem | null = null; private _readStack: ReaderStackItem[] = []; @@ -104,7 +111,7 @@ export class JsonObjectReader implements IJsonReader { return enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] as any; } - public enumProp(enumType: any): T { + public enumProp(enumType: unknown): T { const prop = this.prop(); const num = parseInt(prop); return isNaN(num) @@ -175,6 +182,10 @@ export class JsonObjectReader implements IJsonReader { this.endObject(); } + public unknown(): unknown { + return this.value(this.currentValueType); + } + public string(): string | null { return this.value(JsonValueType.String); } diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts index 763241987..804ee21d7 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/IJsonWriter.ts @@ -9,6 +9,7 @@ export interface IJsonWriter { prop(name: any): void; + unknown(value: unknown, propName?: any): void; string(value: string | null, propName?: any): void; number(value: number | null, propName?: any): void; boolean(value: boolean | null, propName?: any): void; @@ -18,6 +19,9 @@ export interface IJsonWriter { numberArray(value: number[] | null, propName?: any): void; } +/** + * @target web + */ export class JsonObjectWriter implements IJsonWriter { private _objectStack: any[] = []; private _currentPropertyName: string = ''; @@ -70,6 +74,10 @@ export class JsonObjectWriter implements IJsonWriter { this._currentPropertyName = name; } + public unknown(value: unknown, propName?: any): void { + this.writeValue(value, propName); + } + public string(value: string | null, propName?: any): void { this.writeValue(value, propName); } diff --git a/src/model/Font.ts b/src/model/Font.ts index 88ba244df..237f5788a 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -1,7 +1,263 @@ -import { Environment } from '@src/Environment'; import { IJsonReader, JsonValueType } from '@src/io/IJsonReader'; import { IJsonWriter } from '@src/io/IJsonWriter'; +/** + * A very basic font parser which parses the fields according to + * https://www.w3.org/TR/CSS21/fonts.html#propdef-font + */ +class FontParserToken { + public startPos: number; + public endPos: number; + public text: string; + public constructor(text: string, startPos: number, endPos: number) { + this.text = text; + this.startPos = startPos; + this.endPos = endPos; + } +} + +class FontParser { + public style: string = 'normal'; + public variant: string = 'normal'; + public weight: string = 'normal'; + public stretch: string = 'normal'; + public lineHeight: string = 'normal'; + public size: string = '1rem'; + public families: string[] = []; + + private _tokens: FontParserToken[]; + private _currentTokenIndex: number = -1; + private _input: string = ''; + private _currentToken: FontParserToken | null = null; + + public constructor(input: string) { + this._input = input; + this._tokens = this.splitToTokens(input);; + } + + private splitToTokens(input: string): FontParserToken[] { + const tokens: FontParserToken[] = []; + + let startPos = 0; + while (startPos < input.length) { + let endPos = startPos; + while (endPos < input.length && input.charAt(endPos) !== ' ') { + endPos++; + } + + if (endPos > startPos) { + tokens.push(new FontParserToken(input.substring(startPos, endPos), startPos, endPos)); + } + + startPos = endPos + 1;; + } + + return tokens; + } + + public parse() { + this.reset(); + // default font flags + if (this._tokens.length === 1) { + switch (this._currentToken?.text) { + case 'caption': + case 'icon': + case 'menu': + case 'message-box': + case 'small-caption': + case 'status-bar': + case 'inherit': + return; + } + } + + this.fontStyleVariantWeight(); + this.fontSizeLineHeight(); + this.fontFamily(); + } + + private fontFamily() { + if (!this._currentToken) { + throw new Error(`Missing font list`); + } + + const familyListInput = this._input.substr(this._currentToken.startPos).trim(); + let pos = 0; + while (pos < familyListInput.length) { + let c = familyListInput.charAt(pos); + if (c === ' ' || c == ',') { + // skip whitespace and quotes + pos++; + } else if (c === '"' || c === "'") { + // quoted + const endOfString = this.findEndOfQuote(familyListInput, pos + 1, c); + this.families.push(familyListInput.substring(pos + 1, endOfString).split("\\" + c).join(c)); + pos = endOfString + 1; + } else { + // until comma + const endOfString = this.findEndOfQuote(familyListInput, pos + 1, ','); + this.families.push(familyListInput.substring(pos, endOfString).trim()); + pos = endOfString + 1; + } + } + } + + private findEndOfQuote(s: string, pos: number, quoteChar: string): number { + let escaped = false; + while (pos < s.length) { + const c = s.charAt(pos); + + if (!escaped && c === quoteChar) { + return pos; + } + + if (!escaped && c === '\\') { + escaped = true; + } else { + escaped = false; + } + pos++; + } + + return s.length; + } + + private fontSizeLineHeight() { + if (!this._currentToken) { + throw new Error(`Missing font size`); + } + + const parts = this._currentToken.text.split('/'); + if (parts.length >= 3) { + throw new Error(`Invalid font size '${this._currentToken}' specified`); + } + + this.nextToken(); + + if (parts.length >= 2) { + if (parts[1] === '/') { + // size/ line-height (space after slash) + if (!this._currentToken) { + throw new Error('Missing line-height after font size'); + } + this.lineHeight = this._currentToken.text; + this.nextToken(); + } else { + // size/line-height (no spaces) + this.size = parts[0]; + this.lineHeight = parts[1]; + } + } else if (parts.length >= 1) { + this.size = parts[0]; + if (this._currentToken?.text.indexOf('/') === 0) { + // size / line-height (with spaces befor and after slash) + if (this._currentToken.text === '/') { + this.nextToken(); + if (!this._currentToken) { + throw new Error('Missing line-height after font size'); + } + this.lineHeight = this._currentToken.text; + this.nextToken(); + } else { + this.lineHeight = this._currentToken.text.substr(1); + this.nextToken(); + } + } + } else { + throw new Error(`Missing font size`); + } + } + + private nextToken() { + this._currentTokenIndex++; + if (this._currentTokenIndex < this._tokens.length) { + this._currentToken = this._tokens[this._currentTokenIndex]; + } else { + this._currentToken = null; + } + } + + private fontStyleVariantWeight() { + let hasStyle = false; + let hasVariant = false; + let hasWeight = false; + let valuesNeeded = 3; + let ambiguous: string[] = []; + + while (true) { + switch (this._currentToken?.text) { + // ambiguous + case 'normal': + case 'inherit': + ambiguous.push(this._currentToken?.text); + valuesNeeded--; + this.nextToken(); + break; + + // style + case 'italic': + case 'oblique': + this.style = this._currentToken?.text; + hasStyle = true; + valuesNeeded--; + this.nextToken(); + break; + // variant + case 'small-caps': + this.variant = this._currentToken?.text; + hasVariant = true; + valuesNeeded--; + this.nextToken(); + break; + + // weight + case 'bold': + case 'bolder': + case 'lighter': + case '100': + case '200': + case '300': + case '400': + case '500': + case '600': + case '700': + case '800': + case '900': + this.weight = this._currentToken?.text; + hasWeight = true; + valuesNeeded--; + this.nextToken(); + break; + default: + // unknown token -> done with this part + return; + } + + if (valuesNeeded === 0) { + break; + } + } + + while (ambiguous.length > 0) { + const v = ambiguous.pop()!; + if (!hasWeight) { + this.weight = v; + } + else if (!hasVariant) { + this.variant = v; + } + else if (!hasStyle) { + this.style = v; + } + } + } + + private reset() { + this._currentTokenIndex = -1; + this.nextToken(); + } +} + /** * Lists all flags for font styles. */ @@ -9,13 +265,15 @@ export enum FontStyle { /** * No flags. */ - Plain, + Plain = 0, /** * Font is bold - */ Bold, + */ + Bold = 1, /** * Font is italic. - */ Italic + */ + Italic = 2 } /** @@ -106,21 +364,16 @@ export class Font { return new Font(family, size, style); } case JsonValueType.String: - if (!Environment.isRunningInWorker) { - const value = reader.string(); - let el: HTMLElement = document.createElement('span'); - el.setAttribute('style', 'font: ' + value); - let style: CSSStyleDeclaration = el.style; - if (!style.fontFamily) { - style.fontFamily = 'sans-serif'; - } + { + const parser = new FontParser(reader.string()!); + parser.parse(); - let family: string = style.fontFamily; + let family: string = parser.families[0]; if ((family.startsWith("'") && family.endsWith("'")) || (family.startsWith('"') && family.endsWith('"'))) { family = family.substr(1, family.length - 2); } - let fontSizeString: string = style.fontSize.toLowerCase(); + let fontSizeString: string = parser.size.toLowerCase(); let fontSize: number = 0; // as per https://websemantics.uk/articles/font-size-conversion/ switch (fontSizeString) { @@ -165,10 +418,10 @@ export class Font { } let fontStyle: FontStyle = FontStyle.Plain; - if (style.fontStyle === 'italic') { + if (parser.style === 'italic') { fontStyle |= FontStyle.Italic; } - let fontWeightString: string = style.fontWeight.toLowerCase(); + let fontWeightString: string = parser.weight.toLowerCase(); switch (fontWeightString) { case 'normal': case 'lighter': @@ -180,8 +433,6 @@ export class Font { return new Font(family, fontSize, fontStyle); } - - return null; default: return null; } diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 2fba26e61..307f2cc06 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -13,13 +13,13 @@ import { JsonObjectWriter } from '@src/io/IJsonWriter'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further * JSON serialization. - * @target web */ export class JsonConverter { /** * Converts the given score into a JSON encoded string. * @param score The score to serialize. * @returns A JSON encoded string that can be used togehter with for conversion. + * @target web */ public static scoreToJson(score: Score): string { let obj: unknown = JsonConverter.scoreToJsObject(score); @@ -48,6 +48,7 @@ export class JsonConverter { * @param json The JSON string that was created via {@link Score} * @param settings The settings to use during conversion. * @returns The converted score object. + * @target web */ public static jsonToScore(json: string, settings?: Settings): Score { return JsonConverter.jsObjectToScore(json, settings); @@ -66,6 +67,9 @@ export class JsonConverter { return score; } + /** + * @target web + */ public static jsObjectToMidiFile(midi: any): MidiFile { let midi2: MidiFile = new MidiFile(); midi2.division = midi.division; @@ -101,6 +105,9 @@ export class JsonConverter { return midi2; } + /** + * @target web + */ public static midiFileToJsObject(midi: MidiFile): unknown { let midi2: any = {} as any; midi2.division = midi.division; diff --git a/src/util/JsonHelper.ts b/src/util/JsonHelper.ts deleted file mode 100644 index 2cf95651b..000000000 --- a/src/util/JsonHelper.ts +++ /dev/null @@ -1,8 +0,0 @@ -export class JsonHelper { - public static parseEnum(value: string, enumType: any): T { - return (isNaN(parseInt(value)) - ? enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] - : parseInt(value) - ) as any as T; - } -} \ No newline at end of file diff --git a/test/model/Font.test.ts b/test/model/Font.test.ts new file mode 100644 index 000000000..e70591f9c --- /dev/null +++ b/test/model/Font.test.ts @@ -0,0 +1,50 @@ +import { JsonObjectReader } from "@src/io/IJsonReader"; +import { Font, FontStyle } from "@src/model/Font"; + +describe('FontTests', () => { + function parseText(text: string, expected: Font) { + const reader = new JsonObjectReader(text); + const font = Font.fromJson(reader); + expect(font!.family).toEqual(expected.family); + expect(font!.isBold).toEqual(expected.isBold); + expect(font!.isItalic).toEqual(expected.isItalic); + expect(font!.size).toEqual(expected.size); + expect(font!.style).toEqual(expected.style); + } + + it('parses-full', function () { + parseText('italic small-caps bold 12px/1.5em "Arial"', new Font("Arial", 12, FontStyle.Italic | FontStyle.Bold)) + }); + + it('parses-partial-options', function () { + parseText('italic bold 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic | FontStyle.Bold)) + parseText('bold italic 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic | FontStyle.Bold)) + parseText('bold 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Bold)) + parseText('italic 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic)) + }); + + it('parses-no-options', function () { + parseText('12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + }); + + it('parses-line-height-spaces', function () { + parseText('12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px /1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px / 1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px / 1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + }); + + it('parses-multiple-families', function () { + parseText('12px/1.5em Arial, Verdana, sans', new Font("Arial", 12, FontStyle.Plain)) + parseText("12px/1.5em 'Arial', 'Verdana', 'sans'", new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em "Arial", "Verdana", "sans"', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em Arial, "Verdana", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em Arial, \'Verdana\', "sans"', new Font("Arial", 12, FontStyle.Plain)) + }); + it('parses-escaped-quotes', function () { + parseText("12px/1.5em \"Ari\\\"al\"", new Font("Ari\"al", 12, FontStyle.Plain)) + parseText('12px/1.5em \'Ari\\\'al\'', new Font("Ari'al", 12, FontStyle.Plain)) + parseText('12px/1.5em \'Ari\\\'\'', new Font('Ari\'', 12, FontStyle.Plain)) + parseText("12px/1.5em 'Ari\\al'", new Font("Ari\\al", 12, FontStyle.Plain)) + }); +}); \ No newline at end of file From 6d693717398c166a24beae4a54557cdec0354c21 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Tue, 22 Dec 2020 01:10:51 +0100 Subject: [PATCH 13/19] Fixed Csharp tests --- src.compiler/csharp/CSharpAstPrinter.ts | 17 +- src.csharp/AlphaTab.Test/TestPlatform.cs | 4 +- src.csharp/AlphaTab/Core/EcmaScript/Array.cs | 6 +- src.csharp/AlphaTab/Core/JsonObjectReader.cs | 218 ++++++++++++++++--- src.csharp/AlphaTab/Core/JsonObjectWriter.cs | 131 +++++++++-- src.csharp/AlphaTab/Core/TypeHelper.cs | 5 +- src/io/IJsonReader.ts | 2 +- src/io/IJsonWriter.ts | 44 ++-- test/model/JsonConverter.test.ts | 2 +- 9 files changed, 344 insertions(+), 85 deletions(-) diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index e0fad1b4e..fb2a1f695 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -608,13 +608,20 @@ export default class CSharpAstPrinter { this.writeType(arrayType.elementType); this.write('[]'); } else { - if (forNew) { - this.write('System.Collections.Generic.List<'); + const isDynamicArray = arrayType.elementType.nodeType == cs.SyntaxKind.PrimitiveTypeNode + && (arrayType.elementType as cs.PrimitiveTypeNode).type == cs.PrimitiveType.Dynamic; + if (isDynamicArray && !forNew) { + this.write('System.Collections.IList'); } else { - this.write('System.Collections.Generic.IList<'); + if (forNew) { + this.write('System.Collections.Generic.List<'); + } else { + this.write('System.Collections.Generic.IList<'); + } + this.writeType(arrayType.elementType); + this.write('>'); } - this.writeType(arrayType.elementType); - this.write('>'); + } break; diff --git a/src.csharp/AlphaTab.Test/TestPlatform.cs b/src.csharp/AlphaTab.Test/TestPlatform.cs index daf1d5804..06280e1a4 100644 --- a/src.csharp/AlphaTab.Test/TestPlatform.cs +++ b/src.csharp/AlphaTab.Test/TestPlatform.cs @@ -18,7 +18,9 @@ public static async Task LoadFile(string path) public static Task> ListDirectory(string path) { - return Task.FromResult((IList)Directory.EnumerateFiles(path).ToList()); + return Task.FromResult((IList)Directory.EnumerateFiles(path) + .Select(Path.GetFileName) + .ToList()); } } } diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs index 6fd8f802c..ca2c96d1d 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs @@ -1,10 +1,12 @@ -namespace AlphaTab.Core.EcmaScript +using System.Collections; + +namespace AlphaTab.Core.EcmaScript { internal static class Array { public static bool IsArray(object? o) { - return o is System.Array; + return o is IList; } } } diff --git a/src.csharp/AlphaTab/Core/JsonObjectReader.cs b/src.csharp/AlphaTab/Core/JsonObjectReader.cs index 96f80481c..719407b45 100644 --- a/src.csharp/AlphaTab/Core/JsonObjectReader.cs +++ b/src.csharp/AlphaTab/Core/JsonObjectReader.cs @@ -1,94 +1,258 @@ -using System.Collections.Generic; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; using AlphaTab.Io; namespace AlphaTab.Core { public class JsonObjectReader : IJsonReader { - public JsonValueType CurrentValueType { get; } - - public JsonObjectReader(object? value) + private class ReaderStackItem { + public object? Obj { get; set; } + public int CurrentIndex { get; set; } + public string? CurrentProp { get; set; } + public object? CurrentValue { get; set; } + public IList? CurrentObjectKeys { get; set; } } - public void StartObject() + private ReaderStackItem? _currentItem; + private readonly Stack _readStack = new Stack(); + + public JsonValueType CurrentValueType { get; private set; } = JsonValueType.Null; + + public JsonObjectReader(object? value) { - throw new System.NotImplementedException(); + var root = new Dictionary + { + ["root"] = value + }; + SetCurrentObject(root); + NextProp(); } - public void EndObject() + private void UpdateCurrentValueType(object? val) { - throw new System.NotImplementedException(); + switch (TypeHelper.TypeOf(val)) + { + case "undefined": + CurrentValueType = JsonValueType.Null; + break; + case "string": + CurrentValueType = JsonValueType.String; + break; + case "object": + if (val == null) + { + CurrentValueType = JsonValueType.Null; + } + else if (EcmaScript.Array.IsArray(val)) + { + CurrentValueType = JsonValueType.Array; + } + else + { + CurrentValueType = JsonValueType.Object; + } + + break; + case "number": + CurrentValueType = JsonValueType.Number; + break; + case "boolean": + CurrentValueType = JsonValueType.Boolean; + break; + } } - public void StartArray() + private void SetCurrentObject(object current) { - throw new System.NotImplementedException(); + var currentObjectKeys = EcmaScript.Object.Keys(current); + var obj = new ReaderStackItem + { + Obj = current, + CurrentIndex = -1, + CurrentObjectKeys = currentObjectKeys + }; + _readStack.Push(obj); + _currentItem = obj; } - public void EndArray() + public string Prop() { - throw new System.NotImplementedException(); + return _currentItem?.CurrentProp ?? ""; } - public string Prop() + private T ParseEnum(string value) { - throw new System.NotImplementedException(); + return (T) System.Enum.Parse(typeof(T), value, true); } - public T EnumProp(object? enumType) + public T EnumProp(object? enumType) where T : struct { - throw new System.NotImplementedException(); + var prop = Prop(); + var num = Globals.ParseInt(prop); + return Globals.IsNaN(num) + ? ParseEnum(prop) + : (T) (object) num; } public double NumberProp() { - throw new System.NotImplementedException(); + var prop = Prop(); + return Globals.ParseInt(prop); } public bool NextProp() { - throw new System.NotImplementedException(); + var currentItem = _currentItem!; + currentItem.CurrentIndex++; + if (currentItem.CurrentIndex < currentItem.CurrentObjectKeys.Count) + { + currentItem.CurrentProp = currentItem.CurrentObjectKeys[currentItem.CurrentIndex]; + currentItem.CurrentValue = GetProperty(currentItem.Obj, currentItem.CurrentProp); + UpdateCurrentValueType(currentItem.CurrentValue); + return true; + } + + CurrentValueType = JsonValueType.Null; + return false; + } + + private object? GetProperty(object o, string property) + { + if (o is IDictionary d) + { + return d[property]; + } + + return o.GetType() + .GetProperty(property, BindingFlags.Instance | BindingFlags.Public) + ?.GetValue(o); } public bool NextItem() { - throw new System.NotImplementedException(); + var currentItem = _currentItem!; + currentItem.CurrentIndex++; + + if (EcmaScript.Array.IsArray(currentItem.Obj) && + currentItem.CurrentIndex < ((IList) currentItem.Obj).Count) + { + currentItem.CurrentValue = ((IList) currentItem.Obj)[currentItem.CurrentIndex]; + UpdateCurrentValueType(currentItem.CurrentValue); + return true; + } + else + { + return false; + } + } + + public void StartObject() + { + var currentItem = _currentItem; + if (currentItem != null) + { + switch (CurrentValueType) + { + case JsonValueType.Object: + SetCurrentObject(currentItem.CurrentValue!); + break; + case JsonValueType.Array: + SetCurrentObject(currentItem.CurrentValue!); + break; + default: + throw new InvalidOperationException( + $"Cannot start object / array in the current item.item is a {CurrentValueType}"); + } + } + } + + public void EndObject() + { + _readStack.Pop(); + _currentItem = _readStack.Peek(); + } + + public void StartArray() + { + StartObject(); + } + + public void EndArray() + { + EndObject(); } public object? Unknown() { - throw new System.NotImplementedException(); + return ValueClass(CurrentValueType); } public string? String() { - throw new System.NotImplementedException(); + return ValueClass(JsonValueType.String); } - public T? Enum(dynamic enumType) where T : struct + public T? Enum(object? numType) where T : struct { - throw new System.NotImplementedException(); + var currentItem = _currentItem; + if (currentItem != null) + { + switch (CurrentValueType) + { + case JsonValueType.String: + return ParseEnum(currentItem.CurrentValue as string); + case JsonValueType.Number: + return (T) currentItem.CurrentValue; + } + } + + return null; } public double? Number() { - throw new System.NotImplementedException(); + return this.ValueStruct(JsonValueType.Number); } public bool? Boolean() { - throw new System.NotImplementedException(); + return this.ValueStruct(JsonValueType.Boolean); } public IList? StringArray() { - throw new System.NotImplementedException(); + return ValueClass>(JsonValueType.Array); } public IList? NumberArray() { - throw new System.NotImplementedException(); + return ValueClass>(JsonValueType.Array); + } + + private T? ValueClass(JsonValueType type) where T : class + { + var currentItem = _currentItem; + if (currentItem != null && CurrentValueType == type) + { + return (T?) currentItem.CurrentValue; + } + + return null; + } + + private T? ValueStruct(JsonValueType type) where T : struct + { + var currentItem = _currentItem; + if (currentItem != null && CurrentValueType == type) + { + return (T?) currentItem.CurrentValue; + } + + return null; } } } diff --git a/src.csharp/AlphaTab/Core/JsonObjectWriter.cs b/src.csharp/AlphaTab/Core/JsonObjectWriter.cs index 4da80b618..e24bc419b 100644 --- a/src.csharp/AlphaTab/Core/JsonObjectWriter.cs +++ b/src.csharp/AlphaTab/Core/JsonObjectWriter.cs @@ -1,74 +1,157 @@ -using System.Collections.Generic; +using System; +using System.Collections; +using System.Collections.Generic; using AlphaTab.Io; namespace AlphaTab.Core { public class JsonObjectWriter : IJsonWriter { - public object? Result { get; } + private readonly Stack _objectStack = new Stack(); + + private string _currentPropertyName = ""; + + + public object? Result { get; private set; } + public void StartObject() { - throw new System.NotImplementedException(); + if (_objectStack.Count > 0) + { + var newObject = new Dictionary(); + var currentObject = _objectStack.Peek(); + _objectStack.Push(newObject); + + switch (currentObject) + { + case IList l: + l.Add(newObject); + break; + case IDictionary d: + d[_currentPropertyName] = newObject; + break; + default: + throw new InvalidOperationException("invalid object on write stack"); + } + } + else + { + Result = new Dictionary(); + _objectStack.Push(Result); + } } public void EndObject() { - throw new System.NotImplementedException(); + _objectStack.Pop(); } public void StartArray() { - throw new System.NotImplementedException(); + if (_objectStack.Count > 0) + { + var newObject = new List(); + var currentObject = _objectStack.Peek(); + _objectStack.Push(newObject); + + switch (currentObject) + { + case IList l: + l.Add(newObject); + break; + case IDictionary d: + d[_currentPropertyName] = newObject; + break; + default: + throw new InvalidOperationException("invalid object on write stack"); + } + } + else + { + Result = new List(); + _objectStack.Push(Result); + } } public void EndArray() { - throw new System.NotImplementedException(); + _objectStack.Pop(); } - public void Prop(dynamic name) + public void Prop(object? name) { - throw new System.NotImplementedException(); + _currentPropertyName = Convert.ToString(name); } - public void Unknown(object? value, dynamic? propName = default) + public void Unknown(object? value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void String(string? value, dynamic? propName = default) + public void String(string? value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void Number(double? value, dynamic? propName = default) + public void Number(double? value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void Boolean(bool? value, dynamic? propName = default) + public void Boolean(bool? value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void Enum(T value, dynamic? propName = default) + public void Enum(T value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void Null(dynamic? propName = default) + public void Null(object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(null, propName); } - public void StringArray(IList? value, dynamic? propName = default) + public void StringArray(IList? value, object? propName = null) { - throw new System.NotImplementedException(); + WriteValue(value, propName); } - public void NumberArray(IList? value, dynamic? propName = default) + public void NumberArray(IList? value, object? propName = default) { - throw new System.NotImplementedException(); + WriteValue(value, propName); + } + + private void WriteValue(object? value, object? propName) + { + if (_objectStack.Count > 0) + { + var currentObject = _objectStack.Peek(); + switch (currentObject) + { + case IList l: + l.Add(value); + break; + case IDictionary d: + if (propName != null) + { + d[Convert.ToString(propName)] = value; + } + else + { + d[_currentPropertyName] = value; + } + + break; + default: + throw new InvalidOperationException("Cannot add new value to parent"); + } + } + else + { + Result = value; + } } } } diff --git a/src.csharp/AlphaTab/Core/TypeHelper.cs b/src.csharp/AlphaTab/Core/TypeHelper.cs index 6d3e45b02..873cf5373 100644 --- a/src.csharp/AlphaTab/Core/TypeHelper.cs +++ b/src.csharp/AlphaTab/Core/TypeHelper.cs @@ -277,9 +277,9 @@ public static IList Map(this IList source, } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string Substring(this string s, double startIndex, double length) + public static string Substring(this string s, double startIndex, double endIndex) { - return s.Substring((int) startIndex, (int) length); + return s.Substring((int) startIndex, (int) (endIndex - startIndex)); } public static string TypeOf(object? actual) @@ -300,6 +300,7 @@ public static string TypeOf(object? actual) case ulong _: case float _: case double _: + case Enum _: return "number"; default: return "object"; diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts index d41b171dc..3f876703c 100644 --- a/src/io/IJsonReader.ts +++ b/src/io/IJsonReader.ts @@ -17,7 +17,7 @@ export interface IJsonReader { endArray(): void; prop(): string; - enumProp(enumType: unknown): T; + enumProp(enumType: unknown): T; numberProp(): number; nextProp(): boolean; diff --git a/src/io/IJsonWriter.ts b/src/io/IJsonWriter.ts index 804ee21d7..fb7d07443 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/IJsonWriter.ts @@ -7,16 +7,16 @@ export interface IJsonWriter { startArray(): void; endArray(): void; - prop(name: any): void; - - unknown(value: unknown, propName?: any): void; - string(value: string | null, propName?: any): void; - number(value: number | null, propName?: any): void; - boolean(value: boolean | null, propName?: any): void; - enum(value: T, propName?: any): void; - null(propName?: any): void; - stringArray(value: string[] | null, propName?: any): void; - numberArray(value: number[] | null, propName?: any): void; + prop(name: unknown): void; + + unknown(value: unknown, propName?: unknown): void; + string(value: string | null, propName?: unknown): void; + number(value: number | null, propName?: unknown): void; + boolean(value: boolean | null, propName?: unknown): void; + enum(value: T, propName?: unknown): void; + null(propName?: unknown): void; + stringArray(value: string[] | null, propName?: unknown): void; + numberArray(value: number[] | null, propName?: unknown): void; } /** @@ -70,49 +70,49 @@ export class JsonObjectWriter implements IJsonWriter { this._objectStack.pop(); } - public prop(name: any): void { - this._currentPropertyName = name; + public prop(name: unknown): void { + this._currentPropertyName = name as any; } - public unknown(value: unknown, propName?: any): void { + public unknown(value: unknown, propName?: unknown): void { this.writeValue(value, propName); } - public string(value: string | null, propName?: any): void { + public string(value: string | null, propName?: unknown): void { this.writeValue(value, propName); } - public number(value: number | null, propName?: any): void { + public number(value: number | null, propName?: unknown): void { this.writeValue(value, propName); } - public boolean(value: boolean | null, propName?: any): void { + public boolean(value: boolean | null, propName?: unknown): void { this.writeValue(value, propName); } - public enum(value: T, propName?: any): void { + public enum(value: T, propName?: unknown): void { this.writeValue(value, propName); } - public null(propName?: any): void { + public null(propName?: unknown): void { this.writeValue(null, propName); } - public stringArray(value: string[] | null, propName?: any): void { + public stringArray(value: string[] | null, propName?: unknown): void { this.writeValue(value, propName); } - public numberArray(value: number[] | null, propName?: any): void { + public numberArray(value: number[] | null, propName?: unknown): void { this.writeValue(value, propName); } - private writeValue(value: any, propName?: any) { + private writeValue(value: any, propName?: unknown) { if (this._objectStack.length > 0) { const currentObject = this._objectStack[this._objectStack.length - 1]; if (Array.isArray(currentObject)) { this._objectStack.push(value); } else if (typeof propName !== 'undefined') { - currentObject[propName] = value; + currentObject[propName as any] = value; } else { currentObject[this._currentPropertyName] = value; } diff --git a/test/model/JsonConverter.test.ts b/test/model/JsonConverter.test.ts index e773eb53f..1dcb64e49 100644 --- a/test/model/JsonConverter.test.ts +++ b/test/model/JsonConverter.test.ts @@ -50,7 +50,7 @@ describe('JsonConverterTest', () => { expectJsonEqual(expected[i], actual[i], `${path}[${i}]`); } } - } else { + } else if(!Array.isArray(actual)) { const expectedKeys = Object.keys(expected); const actualKeys = Object.keys(actual); From 235e440c9e9672be7954d4d38843d7c38df09db1 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 24 Dec 2020 18:35:10 +0100 Subject: [PATCH 14/19] more shared code and cleanup --- src.compiler/csharp/CSharpAstPrinter.ts | 2 +- src.compiler/csharp/CSharpAstTransformer.ts | 17 +- src.compiler/csharp/CSharpEmitterContext.ts | 16 +- src.compiler/typescript/SerializerEmitter.ts | 19 +- src.csharp/AlphaTab/Core/EcmaScript/Array.cs | 12 + src.csharp/AlphaTab/Core/EcmaScript/Map.cs | 74 +++- src.csharp/AlphaTab/Core/JsonObjectReader.cs | 258 -------------- src.csharp/AlphaTab/Core/JsonObjectWriter.cs | 157 --------- src.csharp/AlphaTab/Core/TypeHelper.cs | 2 + src.csharp/AlphaTab/IO/JsonReader.cs | 17 + src.csharp/AlphaTab/IO/JsonWriter.cs | 17 + src.csharp/AlphaTab/IO/ObjectToMap.cs | 21 ++ src/PlayerSettings.ts | 2 +- src/Settings.ts | 4 +- src/generated/CoreSettingsSerializer.ts | 12 +- src/generated/DisplaySettingsSerializer.ts | 12 +- src/generated/ImporterSettingsSerializer.ts | 12 +- src/generated/NotationSettingsSerializer.ts | 12 +- src/generated/PlayerSettingsSerializer.ts | 12 +- src/generated/RenderingResourcesSerializer.ts | 12 +- src/generated/SettingsSerializer.ts | 14 +- .../SlidePlaybackSettingsSerializer.ts | 12 +- .../VibratoPlaybackSettingsSerializer.ts | 12 +- src/generated/model/AutomationSerializer.ts | 12 +- src/generated/model/BarSerializer.ts | 12 +- src/generated/model/BeatSerializer.ts | 12 +- src/generated/model/BendPointSerializer.ts | 12 +- src/generated/model/ChordSerializer.ts | 12 +- src/generated/model/FermataSerializer.ts | 12 +- .../model/InstrumentArticulationSerializer.ts | 12 +- src/generated/model/MasterBarSerializer.ts | 12 +- src/generated/model/NoteSerializer.ts | 12 +- .../model/PlaybackInformationSerializer.ts | 12 +- .../model/RenderStylesheetSerializer.ts | 12 +- src/generated/model/ScoreSerializer.ts | 12 +- src/generated/model/SectionSerializer.ts | 12 +- src/generated/model/StaffSerializer.ts | 12 +- src/generated/model/TrackSerializer.ts | 12 +- src/generated/model/VoiceSerializer.ts | 12 +- src/io/IJsonReader.ts | 229 ------------- src/io/JsonReader.ts | 323 ++++++++++++++++++ src/io/{IJsonWriter.ts => JsonWriter.ts} | 64 ++-- src/model/Color.ts | 8 +- src/model/Font.ts | 19 +- src/model/JsonConverter.ts | 33 +- src/platform/javascript/AlphaTabWebWorker.ts | 7 +- .../javascript/AlphaTabWorkerScoreRenderer.ts | 10 +- src/platform/javascript/BrowserUiFacade.ts | 6 +- src/rendering/TabBarRenderer.ts | 4 +- test/model/Font.test.ts | 4 +- test/model/JsonConverter.test.ts | 187 ++++++++-- 51 files changed, 892 insertions(+), 922 deletions(-) delete mode 100644 src.csharp/AlphaTab/Core/JsonObjectReader.cs delete mode 100644 src.csharp/AlphaTab/Core/JsonObjectWriter.cs create mode 100644 src.csharp/AlphaTab/IO/JsonReader.cs create mode 100644 src.csharp/AlphaTab/IO/JsonWriter.cs create mode 100644 src.csharp/AlphaTab/IO/ObjectToMap.cs delete mode 100644 src/io/IJsonReader.ts create mode 100644 src/io/JsonReader.ts rename src/io/{IJsonWriter.ts => JsonWriter.ts} (61%) diff --git a/src.compiler/csharp/CSharpAstPrinter.ts b/src.compiler/csharp/CSharpAstPrinter.ts index fb2a1f695..bee2fed26 100644 --- a/src.compiler/csharp/CSharpAstPrinter.ts +++ b/src.compiler/csharp/CSharpAstPrinter.ts @@ -656,7 +656,7 @@ export default class CSharpAstPrinter { this.write('TODO: ' + cs.SyntaxKind[type.nodeType]); break; } - if (type.isNullable && !forNew) { + if (type.isNullable && !forNew && !forTypeConstraint) { this.write('?'); } } diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index 6f4a1cdc0..4108ab7cd 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -433,7 +433,8 @@ export default class CSharpAstTransformer { }; if (p.constraint) { - csTypeParameter.constraint = this.createUnresolvedTypeNode(csTypeParameter, p.constraint); + let constraintType = (ts.isUnionTypeNode(p.constraint) ? p.constraint.types[0] : p.constraint); + csTypeParameter.constraint = this.createUnresolvedTypeNode(csTypeParameter, constraintType); } return csTypeParameter; @@ -576,7 +577,8 @@ export default class CSharpAstTransformer { tsNode: d.arguments[1] } as cs.PrimitiveTypeNode, visibility: cs.Visibility.Public, - tsNode: d + tsNode: d, + skipEmit: this.shouldSkip(d) }; if (csMethod.name.match(/^[^a-zA-Z].*/)) { @@ -1222,16 +1224,7 @@ export default class CSharpAstTransformer { if (classElement.typeParameters && classElement.typeParameters.length > 0) { csMethod.typeParameters = []; classElement.typeParameters.forEach(p => { - const csp = { - parent: csMethod, - name: p.name.text, - nodeType: cs.SyntaxKind.TypeParameterDeclaration, - tsNode: p - } as cs.TypeParameterDeclaration; - if (p.constraint) { - csp.constraint = this.createUnresolvedTypeNode(csp, p.constraint); - } - + const csp = this.visitTypeParameterDeclaration(csMethod, p); csMethod.typeParameters!.push(csp); }); } diff --git a/src.compiler/csharp/CSharpEmitterContext.ts b/src.compiler/csharp/CSharpEmitterContext.ts index 21e19a87b..7663d3e72 100644 --- a/src.compiler/csharp/CSharpEmitterContext.ts +++ b/src.compiler/csharp/CSharpEmitterContext.ts @@ -1,6 +1,7 @@ import * as cs from './CSharpAst'; import * as ts from 'typescript'; import * as path from 'path'; +import { indexOf } from 'lodash'; type SymbolKey = string; @@ -297,10 +298,13 @@ export default class CSharpEmitterContext { return null; case 'Map': const mapType = tsType as ts.TypeReference; + let mapKeyType: cs.TypeNode | null = null; let mapValueType: cs.TypeNode | null = null; if (typeArguments) { + mapKeyType = this.resolveType(typeArguments[0]); mapValueType = this.resolveType(typeArguments[1]); } else if (mapType.typeArguments) { + mapKeyType = this.getTypeFromTsType(node, mapType.typeArguments[0]); mapValueType = this.getTypeFromTsType(node, mapType.typeArguments[1]); } @@ -334,7 +338,7 @@ export default class CSharpEmitterContext { parent: node.parent, tsNode: node.tsNode, reference: this.buildCoreNamespace(tsSymbol) + (isValueType ? 'ValueTypeMap' : 'Map'), - typeArguments: typeArguments + typeArguments: [mapKeyType, mapValueType] } as cs.TypeReference; case 'Array': const arrayType = tsType as ts.TypeReference; @@ -608,6 +612,13 @@ export default class CSharpEmitterContext { return handleNullablePrimitive(cs.PrimitiveType.Dynamic); } + // object -> object + if(tsType.flags === ts.TypeFlags.NonPrimitive && 'objectFlags' in tsType && 'intrinsicName' in tsType) { + const unknown = handleNullablePrimitive(cs.PrimitiveType.Object); + unknown.isNullable = true; + return unknown; + } + // unknown -> object if ((tsType.flags & ts.TypeFlags.Unknown) !== 0) { const unknown = handleNullablePrimitive(cs.PrimitiveType.Object); @@ -947,6 +958,7 @@ export default class CSharpEmitterContext { let declaredType = this.typeChecker.getTypeAtLocation(symbol.declarations[0]); + let contextualTypeNullable = contextualType; contextualType = this.typeChecker.getNonNullableType(contextualType); declaredType = this.typeChecker.getNonNullableType(declaredType); @@ -991,7 +1003,7 @@ export default class CSharpEmitterContext { } return contextualType !== declaredType && !this.isTypeAssignable(contextualType, declaredType) - ? contextualType + ? contextualTypeNullable : null; } shouldSkipSmartCast(contextualType: ts.Type) { diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index a06cebc15..abdc39891 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -135,8 +135,8 @@ function generateFromJsonBody() { function createFromJsonMethod(input: ts.ClassDeclaration, importer: (name: string, module: string) => void) { - importer('IJsonReader', '@src/io/IJsonReader'); - importer('JsonValueType', '@src/io/IJsonReader'); + importer('JsonReader', '@src/io/JsonReader'); + importer('JsonValueType', '@src/io/JsonReader'); return ts.factory.createMethodDeclaration( undefined, [ @@ -165,7 +165,7 @@ function createFromJsonMethod(input: ts.ClassDeclaration, undefined, 'r', undefined, - ts.factory.createTypeReferenceNode('IJsonReader') + ts.factory.createTypeReferenceNode('JsonReader') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), @@ -485,7 +485,7 @@ function createToJsonMethod(program: ts.Program, propertiesToSerialize: JsonProperty[], importer: (name: string, module: string) => void ) { - importer('IJsonWriter', '@src/io/IJsonWriter'); + importer('JsonWriter', '@src/io/JsonWriter'); return ts.factory.createMethodDeclaration( undefined, [ @@ -517,7 +517,7 @@ function createToJsonMethod(program: ts.Program, undefined, 'w', undefined, - ts.factory.createTypeReferenceNode('IJsonWriter') + ts.factory.createTypeReferenceNode('JsonWriter') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), @@ -1031,8 +1031,11 @@ function generateSetPropertyBody(program: ts.Program, } } - const switchExpr = ts.factory.createSwitchStatement(ts.factory.createIdentifier('property'), ts.factory.createCaseBlock(cases)); - statements.unshift(switchExpr); + if(cases.length > 0){ + const switchExpr = ts.factory.createSwitchStatement(ts.factory.createIdentifier('property'), ts.factory.createCaseBlock(cases)); + statements.unshift(switchExpr); + } + statements.push(ts.factory.createReturnStatement(ts.factory.createFalse())); return ts.factory.createBlock(addNewLines(statements)); @@ -1080,7 +1083,7 @@ function createSetPropertyMethod( undefined, 'r', undefined, - ts.factory.createTypeReferenceNode('IJsonReader') + ts.factory.createTypeReferenceNode('JsonReader') ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs index ca2c96d1d..2fb1f32d1 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs @@ -1,4 +1,6 @@ using System.Collections; +using System.Collections.Generic; +using System.Linq; namespace AlphaTab.Core.EcmaScript { @@ -8,5 +10,15 @@ public static bool IsArray(object? o) { return o is IList; } + + public static IList From(IList x) + { + return x; + } + + public static IList From(IEnumerable x) + { + return x.ToList(); + } } } diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Map.cs b/src.csharp/AlphaTab/Core/EcmaScript/Map.cs index 4cfc545a3..8aeb2ce20 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Map.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Map.cs @@ -5,7 +5,12 @@ namespace AlphaTab.Core.EcmaScript { - public class Map : IEnumerable> + public abstract class Map + { + } + + public class Map : Map, IEnumerable>, + IDictionary where TValue : class? { private readonly Dictionary _data; @@ -49,11 +54,44 @@ public void Delete(TKey key) _data.Remove(key); } + void ICollection>.Add(KeyValuePair item) + { + ((ICollection>) _data).Add(item); + } + public void Clear() { _data.Clear(); } + bool ICollection>.Contains(KeyValuePair item) + { + return ((ICollection>) _data).Contains(item); + } + + void ICollection>.CopyTo(KeyValuePair[] array, + int arrayIndex) + { + ((ICollection>) _data).CopyTo(array, arrayIndex); + } + + bool ICollection>.Remove(KeyValuePair item) + { + return ((ICollection>) _data).Remove(item); + } + + int ICollection>.Count => + ((ICollection>) _data).Count; + + bool ICollection>.IsReadOnly => + ((ICollection>) _data).IsReadOnly; + + IEnumerator> IEnumerable>. + GetEnumerator() + { + return ((IEnumerable>) _data).GetEnumerator(); + } + public IEnumerator> GetEnumerator() { return _data.Select(d => new MapEntry(d.Key, d.Value)).GetEnumerator(); @@ -80,5 +118,39 @@ public void ForEach(Action callback) } } + public IEnumerable Keys() + { + return _data.Keys; + } + + void IDictionary.Add(TKey key, TValue value) + { + _data.Add(key, value); + } + + bool IDictionary.ContainsKey(TKey key) + { + return _data.ContainsKey(key); + } + + bool IDictionary.Remove(TKey key) + { + return _data.Remove(key); + } + + bool IDictionary.TryGetValue(TKey key, out TValue value) + { + return _data.TryGetValue(key, out value); + } + + TValue IDictionary.this[TKey key] + { + get => _data[key]; + set => _data[key] = value; + } + + ICollection IDictionary.Keys => _data.Keys; + + ICollection IDictionary.Values => _data.Values; } } diff --git a/src.csharp/AlphaTab/Core/JsonObjectReader.cs b/src.csharp/AlphaTab/Core/JsonObjectReader.cs deleted file mode 100644 index 719407b45..000000000 --- a/src.csharp/AlphaTab/Core/JsonObjectReader.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Reflection; -using AlphaTab.Io; - -namespace AlphaTab.Core -{ - public class JsonObjectReader : IJsonReader - { - private class ReaderStackItem - { - public object? Obj { get; set; } - public int CurrentIndex { get; set; } - public string? CurrentProp { get; set; } - public object? CurrentValue { get; set; } - public IList? CurrentObjectKeys { get; set; } - } - - private ReaderStackItem? _currentItem; - private readonly Stack _readStack = new Stack(); - - public JsonValueType CurrentValueType { get; private set; } = JsonValueType.Null; - - public JsonObjectReader(object? value) - { - var root = new Dictionary - { - ["root"] = value - }; - SetCurrentObject(root); - NextProp(); - } - - private void UpdateCurrentValueType(object? val) - { - switch (TypeHelper.TypeOf(val)) - { - case "undefined": - CurrentValueType = JsonValueType.Null; - break; - case "string": - CurrentValueType = JsonValueType.String; - break; - case "object": - if (val == null) - { - CurrentValueType = JsonValueType.Null; - } - else if (EcmaScript.Array.IsArray(val)) - { - CurrentValueType = JsonValueType.Array; - } - else - { - CurrentValueType = JsonValueType.Object; - } - - break; - case "number": - CurrentValueType = JsonValueType.Number; - break; - case "boolean": - CurrentValueType = JsonValueType.Boolean; - break; - } - } - - private void SetCurrentObject(object current) - { - var currentObjectKeys = EcmaScript.Object.Keys(current); - var obj = new ReaderStackItem - { - Obj = current, - CurrentIndex = -1, - CurrentObjectKeys = currentObjectKeys - }; - _readStack.Push(obj); - _currentItem = obj; - } - - public string Prop() - { - return _currentItem?.CurrentProp ?? ""; - } - - private T ParseEnum(string value) - { - return (T) System.Enum.Parse(typeof(T), value, true); - } - - public T EnumProp(object? enumType) where T : struct - { - var prop = Prop(); - var num = Globals.ParseInt(prop); - return Globals.IsNaN(num) - ? ParseEnum(prop) - : (T) (object) num; - } - - public double NumberProp() - { - var prop = Prop(); - return Globals.ParseInt(prop); - } - - public bool NextProp() - { - var currentItem = _currentItem!; - currentItem.CurrentIndex++; - if (currentItem.CurrentIndex < currentItem.CurrentObjectKeys.Count) - { - currentItem.CurrentProp = currentItem.CurrentObjectKeys[currentItem.CurrentIndex]; - currentItem.CurrentValue = GetProperty(currentItem.Obj, currentItem.CurrentProp); - UpdateCurrentValueType(currentItem.CurrentValue); - return true; - } - - CurrentValueType = JsonValueType.Null; - return false; - } - - private object? GetProperty(object o, string property) - { - if (o is IDictionary d) - { - return d[property]; - } - - return o.GetType() - .GetProperty(property, BindingFlags.Instance | BindingFlags.Public) - ?.GetValue(o); - } - - public bool NextItem() - { - var currentItem = _currentItem!; - currentItem.CurrentIndex++; - - if (EcmaScript.Array.IsArray(currentItem.Obj) && - currentItem.CurrentIndex < ((IList) currentItem.Obj).Count) - { - currentItem.CurrentValue = ((IList) currentItem.Obj)[currentItem.CurrentIndex]; - UpdateCurrentValueType(currentItem.CurrentValue); - return true; - } - else - { - return false; - } - } - - public void StartObject() - { - var currentItem = _currentItem; - if (currentItem != null) - { - switch (CurrentValueType) - { - case JsonValueType.Object: - SetCurrentObject(currentItem.CurrentValue!); - break; - case JsonValueType.Array: - SetCurrentObject(currentItem.CurrentValue!); - break; - default: - throw new InvalidOperationException( - $"Cannot start object / array in the current item.item is a {CurrentValueType}"); - } - } - } - - public void EndObject() - { - _readStack.Pop(); - _currentItem = _readStack.Peek(); - } - - public void StartArray() - { - StartObject(); - } - - public void EndArray() - { - EndObject(); - } - - public object? Unknown() - { - return ValueClass(CurrentValueType); - } - - public string? String() - { - return ValueClass(JsonValueType.String); - } - - public T? Enum(object? numType) where T : struct - { - var currentItem = _currentItem; - if (currentItem != null) - { - switch (CurrentValueType) - { - case JsonValueType.String: - return ParseEnum(currentItem.CurrentValue as string); - case JsonValueType.Number: - return (T) currentItem.CurrentValue; - } - } - - return null; - } - - public double? Number() - { - return this.ValueStruct(JsonValueType.Number); - } - - public bool? Boolean() - { - return this.ValueStruct(JsonValueType.Boolean); - } - - public IList? StringArray() - { - return ValueClass>(JsonValueType.Array); - } - - public IList? NumberArray() - { - return ValueClass>(JsonValueType.Array); - } - - private T? ValueClass(JsonValueType type) where T : class - { - var currentItem = _currentItem; - if (currentItem != null && CurrentValueType == type) - { - return (T?) currentItem.CurrentValue; - } - - return null; - } - - private T? ValueStruct(JsonValueType type) where T : struct - { - var currentItem = _currentItem; - if (currentItem != null && CurrentValueType == type) - { - return (T?) currentItem.CurrentValue; - } - - return null; - } - } -} diff --git a/src.csharp/AlphaTab/Core/JsonObjectWriter.cs b/src.csharp/AlphaTab/Core/JsonObjectWriter.cs deleted file mode 100644 index e24bc419b..000000000 --- a/src.csharp/AlphaTab/Core/JsonObjectWriter.cs +++ /dev/null @@ -1,157 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using AlphaTab.Io; - -namespace AlphaTab.Core -{ - public class JsonObjectWriter : IJsonWriter - { - private readonly Stack _objectStack = new Stack(); - - private string _currentPropertyName = ""; - - - public object? Result { get; private set; } - - public void StartObject() - { - if (_objectStack.Count > 0) - { - var newObject = new Dictionary(); - var currentObject = _objectStack.Peek(); - _objectStack.Push(newObject); - - switch (currentObject) - { - case IList l: - l.Add(newObject); - break; - case IDictionary d: - d[_currentPropertyName] = newObject; - break; - default: - throw new InvalidOperationException("invalid object on write stack"); - } - } - else - { - Result = new Dictionary(); - _objectStack.Push(Result); - } - } - - public void EndObject() - { - _objectStack.Pop(); - } - - public void StartArray() - { - if (_objectStack.Count > 0) - { - var newObject = new List(); - var currentObject = _objectStack.Peek(); - _objectStack.Push(newObject); - - switch (currentObject) - { - case IList l: - l.Add(newObject); - break; - case IDictionary d: - d[_currentPropertyName] = newObject; - break; - default: - throw new InvalidOperationException("invalid object on write stack"); - } - } - else - { - Result = new List(); - _objectStack.Push(Result); - } - } - - public void EndArray() - { - _objectStack.Pop(); - } - - public void Prop(object? name) - { - _currentPropertyName = Convert.ToString(name); - } - - public void Unknown(object? value, object? propName = null) - { - WriteValue(value, propName); - } - - public void String(string? value, object? propName = null) - { - WriteValue(value, propName); - } - - public void Number(double? value, object? propName = null) - { - WriteValue(value, propName); - } - - public void Boolean(bool? value, object? propName = null) - { - WriteValue(value, propName); - } - - public void Enum(T value, object? propName = null) - { - WriteValue(value, propName); - } - - public void Null(object? propName = null) - { - WriteValue(null, propName); - } - - public void StringArray(IList? value, object? propName = null) - { - WriteValue(value, propName); - } - - public void NumberArray(IList? value, object? propName = default) - { - WriteValue(value, propName); - } - - private void WriteValue(object? value, object? propName) - { - if (_objectStack.Count > 0) - { - var currentObject = _objectStack.Peek(); - switch (currentObject) - { - case IList l: - l.Add(value); - break; - case IDictionary d: - if (propName != null) - { - d[Convert.ToString(propName)] = value; - } - else - { - d[_currentPropertyName] = value; - } - - break; - default: - throw new InvalidOperationException("Cannot add new value to parent"); - } - } - else - { - Result = value; - } - } - } -} diff --git a/src.csharp/AlphaTab/Core/TypeHelper.cs b/src.csharp/AlphaTab/Core/TypeHelper.cs index 873cf5373..d18083523 100644 --- a/src.csharp/AlphaTab/Core/TypeHelper.cs +++ b/src.csharp/AlphaTab/Core/TypeHelper.cs @@ -302,6 +302,8 @@ public static string TypeOf(object? actual) case double _: case Enum _: return "number"; + case null: + return "undefined"; default: return "object"; } diff --git a/src.csharp/AlphaTab/IO/JsonReader.cs b/src.csharp/AlphaTab/IO/JsonReader.cs new file mode 100644 index 000000000..1970382ed --- /dev/null +++ b/src.csharp/AlphaTab/IO/JsonReader.cs @@ -0,0 +1,17 @@ +using System; + +namespace AlphaTab.Io +{ + partial class JsonReader + { + private T ParseEnum(string value, object? enumType) + { + return (T) System.Enum.Parse(typeof(T), value, true); + } + + private T NumberToEnum(double value) + { + return (T)(object)(int) value; + } + } +} diff --git a/src.csharp/AlphaTab/IO/JsonWriter.cs b/src.csharp/AlphaTab/IO/JsonWriter.cs new file mode 100644 index 000000000..608df08f2 --- /dev/null +++ b/src.csharp/AlphaTab/IO/JsonWriter.cs @@ -0,0 +1,17 @@ +using System; +using System.Globalization; + +namespace AlphaTab.Io +{ + partial class JsonWriter + { + private double EnumToNumber(T enumValue) + { + if (enumValue is IConvertible c) + { + return c.ToDouble(CultureInfo.InvariantCulture); + } + return double.NaN; + } + } +} diff --git a/src.csharp/AlphaTab/IO/ObjectToMap.cs b/src.csharp/AlphaTab/IO/ObjectToMap.cs new file mode 100644 index 000000000..6b737ffa2 --- /dev/null +++ b/src.csharp/AlphaTab/IO/ObjectToMap.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace AlphaTab.Io +{ + partial class ReaderStackItem + { + private static IDictionary? ObjectToMap(object? obj) + { + switch (obj) + { + case null: + return null; + case IDictionary d: + return d; + default: + throw new ArgumentException("Can only handle IDictionary in JsonReader"); + } + } + } +} diff --git a/src/PlayerSettings.ts b/src/PlayerSettings.ts index f7bf0fb49..eb09ca1e7 100644 --- a/src/PlayerSettings.ts +++ b/src/PlayerSettings.ts @@ -96,7 +96,7 @@ export class SlidePlaybackSettings { */ export class PlayerSettings { /** - * Gets or sets the URl of the sound font to be loaded. + * Gets or sets the URL of the sound font to be loaded. */ public soundFont: string | null = null; diff --git a/src/Settings.ts b/src/Settings.ts index 7df28b0cd..27ed5d7d8 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -4,7 +4,7 @@ import { ImporterSettings } from '@src/ImporterSettings'; import { FingeringMode, NotationMode, NotationSettings, NotationElement } from '@src/NotationSettings'; import { PlayerSettings } from '@src/PlayerSettings'; import { SettingsSerializer } from './generated/SettingsSerializer'; -import { JsonObjectReader } from './io/IJsonReader'; +import { JsonReader } from './io/JsonReader'; /** * This public class contains instance specific settings for alphaTab @@ -16,7 +16,7 @@ export class Settings { */ public fillFromDataAttributes(dataAttributes: Map): void { dataAttributes.forEach((v, k) => { - SettingsSerializer.setProperty(this, k.toLowerCase(), new JsonObjectReader(v)); + SettingsSerializer.setProperty(this, k.toLowerCase(), new JsonReader(v)); }); } diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index f8ec51e51..5ce3437b7 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -4,12 +4,12 @@ // the code is regenerated. // import { CoreSettings } from "@src/CoreSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { LogLevel } from "@src/LogLevel"; export class CoreSettingsSerializer { - public static fromJson(obj: CoreSettings, r: IJsonReader): void { + public static fromJson(obj: CoreSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -19,7 +19,7 @@ export class CoreSettingsSerializer { } r.endObject(); } - public static toJson(obj: CoreSettings | null, w: IJsonWriter): void { + public static toJson(obj: CoreSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -44,7 +44,7 @@ export class CoreSettingsSerializer { w.boolean(obj.includeNoteBounds, "includeNoteBounds"); w.endObject(); } - public static setProperty(obj: CoreSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: CoreSettings, property: string, r: JsonReader): boolean { switch (property) { /*@target web*/ case "scriptfile": diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts index d7797536e..145b4cbd5 100644 --- a/src/generated/DisplaySettingsSerializer.ts +++ b/src/generated/DisplaySettingsSerializer.ts @@ -4,14 +4,14 @@ // the code is regenerated. // import { DisplaySettings } from "@src/DisplaySettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { RenderingResourcesSerializer } from "@src/generated/RenderingResourcesSerializer"; import { LayoutMode } from "@src/DisplaySettings"; import { StaveProfile } from "@src/DisplaySettings"; export class DisplaySettingsSerializer { - public static fromJson(obj: DisplaySettings, r: IJsonReader): void { + public static fromJson(obj: DisplaySettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -21,7 +21,7 @@ export class DisplaySettingsSerializer { } r.endObject(); } - public static toJson(obj: DisplaySettings | null, w: IJsonWriter): void { + public static toJson(obj: DisplaySettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -40,7 +40,7 @@ export class DisplaySettingsSerializer { w.numberArray(obj.padding, "padding"); w.endObject(); } - public static setProperty(obj: DisplaySettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: DisplaySettings, property: string, r: JsonReader): boolean { switch (property) { case "scale": obj.scale = (r.number()!); diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts index 193e3d968..cc325b4ea 100644 --- a/src/generated/ImporterSettingsSerializer.ts +++ b/src/generated/ImporterSettingsSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { ImporterSettings } from "@src/ImporterSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class ImporterSettingsSerializer { - public static fromJson(obj: ImporterSettings, r: IJsonReader): void { + public static fromJson(obj: ImporterSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class ImporterSettingsSerializer { } r.endObject(); } - public static toJson(obj: ImporterSettings | null, w: IJsonWriter): void { + public static toJson(obj: ImporterSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -28,7 +28,7 @@ export class ImporterSettingsSerializer { w.boolean(obj.mergePartGroupsInMusicXml, "mergePartGroupsInMusicXml"); w.endObject(); } - public static setProperty(obj: ImporterSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: ImporterSettings, property: string, r: JsonReader): boolean { switch (property) { case "encoding": obj.encoding = (r.string()!); diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 5ae223081..26a39f615 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -4,15 +4,15 @@ // the code is regenerated. // import { NotationSettings } from "@src/NotationSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { NotationMode } from "@src/NotationSettings"; import { FingeringMode } from "@src/NotationSettings"; import { NotationElement } from "@src/NotationSettings"; import { TabRhythmMode } from "@src/NotationSettings"; export class NotationSettingsSerializer { - public static fromJson(obj: NotationSettings, r: IJsonReader): void { + public static fromJson(obj: NotationSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -22,7 +22,7 @@ export class NotationSettingsSerializer { } r.endObject(); } - public static toJson(obj: NotationSettings | null, w: IJsonWriter): void { + public static toJson(obj: NotationSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -44,7 +44,7 @@ export class NotationSettingsSerializer { w.number(obj.slurHeight, "slurHeight"); w.endObject(); } - public static setProperty(obj: NotationSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: NotationSettings, property: string, r: JsonReader): boolean { switch (property) { case "notationmode": obj.notationMode = (r.enum(NotationMode)!); diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index 71ec678fc..4d9fcb0a6 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -4,12 +4,12 @@ // the code is regenerated. // import { PlayerSettings } from "@src/PlayerSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { - public static fromJson(obj: PlayerSettings, r: IJsonReader): void { + public static fromJson(obj: PlayerSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -19,7 +19,7 @@ export class PlayerSettingsSerializer { } r.endObject(); } - public static toJson(obj: PlayerSettings | null, w: IJsonWriter): void { + public static toJson(obj: PlayerSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -39,7 +39,7 @@ export class PlayerSettingsSerializer { w.boolean(obj.playTripletFeel, "playTripletFeel"); w.endObject(); } - public static setProperty(obj: PlayerSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: PlayerSettings, property: string, r: JsonReader): boolean { switch (property) { case "soundfont": obj.soundFont = r.string(); diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index 81233633b..2ed794250 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -4,13 +4,13 @@ // the code is regenerated. // import { RenderingResources } from "@src/RenderingResources"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { Font } from "@src/model/Font"; import { Color } from "@src/model/Color"; export class RenderingResourcesSerializer { - public static fromJson(obj: RenderingResources, r: IJsonReader): void { + public static fromJson(obj: RenderingResources, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -20,7 +20,7 @@ export class RenderingResourcesSerializer { } r.endObject(); } - public static toJson(obj: RenderingResources | null, w: IJsonWriter): void { + public static toJson(obj: RenderingResources | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -62,7 +62,7 @@ export class RenderingResourcesSerializer { Color.toJson(obj.scoreInfoColor, w); w.endObject(); } - public static setProperty(obj: RenderingResources, property: string, r: IJsonReader): boolean { + public static setProperty(obj: RenderingResources, property: string, r: JsonReader): boolean { switch (property) { case "copyrightfont": obj.copyrightFont = (Font.fromJson(r)!); diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts index 97427a04f..918f30d4a 100644 --- a/src/generated/SettingsSerializer.ts +++ b/src/generated/SettingsSerializer.ts @@ -4,16 +4,16 @@ // the code is regenerated. // import { Settings } from "@src/Settings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { CoreSettingsSerializer } from "@src/generated/CoreSettingsSerializer"; import { DisplaySettingsSerializer } from "@src/generated/DisplaySettingsSerializer"; import { NotationSettingsSerializer } from "@src/generated/NotationSettingsSerializer"; import { ImporterSettingsSerializer } from "@src/generated/ImporterSettingsSerializer"; import { PlayerSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; export class SettingsSerializer { - public static fromJson(obj: Settings, r: IJsonReader): void { + public static fromJson(obj: Settings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -23,7 +23,7 @@ export class SettingsSerializer { } r.endObject(); } - public static toJson(obj: Settings | null, w: IJsonWriter): void { + public static toJson(obj: Settings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -41,9 +41,7 @@ export class SettingsSerializer { PlayerSettingsSerializer.toJson(obj.player, w); w.endObject(); } - public static setProperty(obj: Settings, property: string, r: IJsonReader): boolean { - switch (property) { - } + public static setProperty(obj: Settings, property: string, r: JsonReader): boolean { if (["core", ""].indexOf(property) >= 0) { CoreSettingsSerializer.fromJson(obj.core, r); return true; diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts index c10f15ff0..af7194923 100644 --- a/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { SlidePlaybackSettings } from "@src/PlayerSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class SlidePlaybackSettingsSerializer { - public static fromJson(obj: SlidePlaybackSettings, r: IJsonReader): void { + public static fromJson(obj: SlidePlaybackSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class SlidePlaybackSettingsSerializer { } r.endObject(); } - public static toJson(obj: SlidePlaybackSettings | null, w: IJsonWriter): void { + public static toJson(obj: SlidePlaybackSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -29,7 +29,7 @@ export class SlidePlaybackSettingsSerializer { w.number(obj.shiftSlideDurationRatio, "shiftSlideDurationRatio"); w.endObject(); } - public static setProperty(obj: SlidePlaybackSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: SlidePlaybackSettings, property: string, r: JsonReader): boolean { switch (property) { case "simpleslidepitchoffset": obj.simpleSlidePitchOffset = (r.number()!); diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts index c738d857a..752c5f59f 100644 --- a/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { VibratoPlaybackSettings } from "@src/PlayerSettings"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class VibratoPlaybackSettingsSerializer { - public static fromJson(obj: VibratoPlaybackSettings, r: IJsonReader): void { + public static fromJson(obj: VibratoPlaybackSettings, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class VibratoPlaybackSettingsSerializer { } r.endObject(); } - public static toJson(obj: VibratoPlaybackSettings | null, w: IJsonWriter): void { + public static toJson(obj: VibratoPlaybackSettings | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -34,7 +34,7 @@ export class VibratoPlaybackSettingsSerializer { w.number(obj.beatSlightAmplitude, "beatSlightAmplitude"); w.endObject(); } - public static setProperty(obj: VibratoPlaybackSettings, property: string, r: IJsonReader): boolean { + public static setProperty(obj: VibratoPlaybackSettings, property: string, r: JsonReader): boolean { switch (property) { case "notewidelength": obj.noteWideLength = (r.number()!); diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts index d137eb664..a558f21ec 100644 --- a/src/generated/model/AutomationSerializer.ts +++ b/src/generated/model/AutomationSerializer.ts @@ -4,12 +4,12 @@ // the code is regenerated. // import { Automation } from "@src/model/Automation"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { AutomationType } from "@src/model/Automation"; export class AutomationSerializer { - public static fromJson(obj: Automation, r: IJsonReader): void { + public static fromJson(obj: Automation, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -19,7 +19,7 @@ export class AutomationSerializer { } r.endObject(); } - public static toJson(obj: Automation | null, w: IJsonWriter): void { + public static toJson(obj: Automation | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -32,7 +32,7 @@ export class AutomationSerializer { w.string(obj.text, "text"); w.endObject(); } - public static setProperty(obj: Automation, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Automation, property: string, r: JsonReader): boolean { switch (property) { case "islinear": obj.isLinear = (r.boolean()!); diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index ce27f9bcf..11a2a7a56 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -4,16 +4,16 @@ // the code is regenerated. // import { Bar } from "@src/model/Bar"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { VoiceSerializer } from "@src/generated/model/VoiceSerializer"; import { Clef } from "@src/model/Clef"; import { Ottavia } from "@src/model/Ottavia"; import { Voice } from "@src/model/Voice"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { - public static fromJson(obj: Bar, r: IJsonReader): void { + public static fromJson(obj: Bar, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -23,7 +23,7 @@ export class BarSerializer { } r.endObject(); } - public static toJson(obj: Bar | null, w: IJsonWriter): void { + public static toJson(obj: Bar | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -42,7 +42,7 @@ export class BarSerializer { w.enum(obj.simileMark, "simileMark"); w.endObject(); } - public static setProperty(obj: Bar, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Bar, property: string, r: JsonReader): boolean { switch (property) { case "id": obj.id = (r.number()!); diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index ffe721989..00e645303 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -4,9 +4,9 @@ // the code is regenerated. // import { Beat } from "@src/model/Beat"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { NoteSerializer } from "@src/generated/model/NoteSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; @@ -26,7 +26,7 @@ import { DynamicValue } from "@src/model/DynamicValue"; import { BeamDirection } from "@src/rendering/utils/BeamDirection"; import { BeatBeamingMode } from "@src/model/Beat"; export class BeatSerializer { - public static fromJson(obj: Beat, r: IJsonReader): void { + public static fromJson(obj: Beat, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -36,7 +36,7 @@ export class BeatSerializer { } r.endObject(); } - public static toJson(obj: Beat | null, w: IJsonWriter): void { + public static toJson(obj: Beat | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -98,7 +98,7 @@ export class BeatSerializer { w.enum(obj.beamingMode, "beamingMode"); w.endObject(); } - public static setProperty(obj: Beat, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Beat, property: string, r: JsonReader): boolean { switch (property) { case "id": obj.id = (r.number()!); diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts index 68ff7cb24..c9e51e8fc 100644 --- a/src/generated/model/BendPointSerializer.ts +++ b/src/generated/model/BendPointSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { BendPoint } from "@src/model/BendPoint"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class BendPointSerializer { - public static fromJson(obj: BendPoint, r: IJsonReader): void { + public static fromJson(obj: BendPoint, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class BendPointSerializer { } r.endObject(); } - public static toJson(obj: BendPoint | null, w: IJsonWriter): void { + public static toJson(obj: BendPoint | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -28,7 +28,7 @@ export class BendPointSerializer { w.number(obj.value, "value"); w.endObject(); } - public static setProperty(obj: BendPoint, property: string, r: IJsonReader): boolean { + public static setProperty(obj: BendPoint, property: string, r: JsonReader): boolean { switch (property) { case "offset": obj.offset = (r.number()!); diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts index 47e8ce5b5..7a2f9428b 100644 --- a/src/generated/model/ChordSerializer.ts +++ b/src/generated/model/ChordSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { Chord } from "@src/model/Chord"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class ChordSerializer { - public static fromJson(obj: Chord, r: IJsonReader): void { + public static fromJson(obj: Chord, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class ChordSerializer { } r.endObject(); } - public static toJson(obj: Chord | null, w: IJsonWriter): void { + public static toJson(obj: Chord | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -33,7 +33,7 @@ export class ChordSerializer { w.boolean(obj.showFingering, "showFingering"); w.endObject(); } - public static setProperty(obj: Chord, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Chord, property: string, r: JsonReader): boolean { switch (property) { case "name": obj.name = (r.string()!); diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts index 88cb1ce2e..5aace2e09 100644 --- a/src/generated/model/FermataSerializer.ts +++ b/src/generated/model/FermataSerializer.ts @@ -4,12 +4,12 @@ // the code is regenerated. // import { Fermata } from "@src/model/Fermata"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { FermataType } from "@src/model/Fermata"; export class FermataSerializer { - public static fromJson(obj: Fermata, r: IJsonReader): void { + public static fromJson(obj: Fermata, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -19,7 +19,7 @@ export class FermataSerializer { } r.endObject(); } - public static toJson(obj: Fermata | null, w: IJsonWriter): void { + public static toJson(obj: Fermata | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -29,7 +29,7 @@ export class FermataSerializer { w.number(obj.length, "length"); w.endObject(); } - public static setProperty(obj: Fermata, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Fermata, property: string, r: JsonReader): boolean { switch (property) { case "type": obj.type = (r.enum(FermataType)!); diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts index 34573188f..00332d659 100644 --- a/src/generated/model/InstrumentArticulationSerializer.ts +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -4,13 +4,13 @@ // the code is regenerated. // import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; import { TextBaseline } from "@src/platform/ICanvas"; export class InstrumentArticulationSerializer { - public static fromJson(obj: InstrumentArticulation, r: IJsonReader): void { + public static fromJson(obj: InstrumentArticulation, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -20,7 +20,7 @@ export class InstrumentArticulationSerializer { } r.endObject(); } - public static toJson(obj: InstrumentArticulation | null, w: IJsonWriter): void { + public static toJson(obj: InstrumentArticulation | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -35,7 +35,7 @@ export class InstrumentArticulationSerializer { w.number(obj.outputMidiNumber, "outputMidiNumber"); w.endObject(); } - public static setProperty(obj: InstrumentArticulation, property: string, r: IJsonReader): boolean { + public static setProperty(obj: InstrumentArticulation, property: string, r: JsonReader): boolean { switch (property) { case "staffline": obj.staffLine = (r.number()!); diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index ec41b5af0..22ee368dc 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -4,9 +4,9 @@ // the code is regenerated. // import { MasterBar } from "@src/model/MasterBar"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { SectionSerializer } from "@src/generated/model/SectionSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { FermataSerializer } from "@src/generated/model/FermataSerializer"; @@ -17,7 +17,7 @@ import { Section } from "@src/model/Section"; import { Automation } from "@src/model/Automation"; import { Fermata } from "@src/model/Fermata"; export class MasterBarSerializer { - public static fromJson(obj: MasterBar, r: IJsonReader): void { + public static fromJson(obj: MasterBar, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -27,7 +27,7 @@ export class MasterBarSerializer { } r.endObject(); } - public static toJson(obj: MasterBar | null, w: IJsonWriter): void { + public static toJson(obj: MasterBar | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -64,7 +64,7 @@ export class MasterBarSerializer { w.boolean(obj.isAnacrusis, "isAnacrusis"); w.endObject(); } - public static setProperty(obj: MasterBar, property: string, r: IJsonReader): boolean { + public static setProperty(obj: MasterBar, property: string, r: JsonReader): boolean { switch (property) { case "alternateendings": obj.alternateEndings = (r.number()!); diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index 995d61e04..1eaf2a7fe 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -4,9 +4,9 @@ // the code is regenerated. // import { Note } from "@src/model/Note"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; import { AccentuationType } from "@src/model/AccentuationType"; import { BendType } from "@src/model/BendType"; @@ -21,7 +21,7 @@ import { Duration } from "@src/model/Duration"; import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; import { DynamicValue } from "@src/model/DynamicValue"; export class NoteSerializer { - public static fromJson(obj: Note, r: IJsonReader): void { + public static fromJson(obj: Note, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -31,7 +31,7 @@ export class NoteSerializer { } r.endObject(); } - public static toJson(obj: Note | null, w: IJsonWriter): void { + public static toJson(obj: Note | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -87,7 +87,7 @@ export class NoteSerializer { w.boolean(obj.hasEffectSlur, "hasEffectSlur"); w.endObject(); } - public static setProperty(obj: Note, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Note, property: string, r: JsonReader): boolean { switch (property) { case "id": obj.id = (r.number()!); diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts index f452e69fe..59dabd05f 100644 --- a/src/generated/model/PlaybackInformationSerializer.ts +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { PlaybackInformation } from "@src/model/PlaybackInformation"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class PlaybackInformationSerializer { - public static fromJson(obj: PlaybackInformation, r: IJsonReader): void { + public static fromJson(obj: PlaybackInformation, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class PlaybackInformationSerializer { } r.endObject(); } - public static toJson(obj: PlaybackInformation | null, w: IJsonWriter): void { + public static toJson(obj: PlaybackInformation | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -34,7 +34,7 @@ export class PlaybackInformationSerializer { w.boolean(obj.isSolo, "isSolo"); w.endObject(); } - public static setProperty(obj: PlaybackInformation, property: string, r: IJsonReader): boolean { + public static setProperty(obj: PlaybackInformation, property: string, r: JsonReader): boolean { switch (property) { case "volume": obj.volume = (r.number()!); diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts index 548b559f4..de5b901f9 100644 --- a/src/generated/model/RenderStylesheetSerializer.ts +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { RenderStylesheet } from "@src/model/RenderStylesheet"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class RenderStylesheetSerializer { - public static fromJson(obj: RenderStylesheet, r: IJsonReader): void { + public static fromJson(obj: RenderStylesheet, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class RenderStylesheetSerializer { } r.endObject(); } - public static toJson(obj: RenderStylesheet | null, w: IJsonWriter): void { + public static toJson(obj: RenderStylesheet | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -27,7 +27,7 @@ export class RenderStylesheetSerializer { w.boolean(obj.hideDynamics, "hideDynamics"); w.endObject(); } - public static setProperty(obj: RenderStylesheet, property: string, r: IJsonReader): boolean { + public static setProperty(obj: RenderStylesheet, property: string, r: JsonReader): boolean { switch (property) { case "hidedynamics": obj.hideDynamics = (r.boolean()!); diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index b37611499..1ff650dfa 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -4,16 +4,16 @@ // the code is regenerated. // import { Score } from "@src/model/Score"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { MasterBarSerializer } from "@src/generated/model/MasterBarSerializer"; import { TrackSerializer } from "@src/generated/model/TrackSerializer"; import { RenderStylesheetSerializer } from "@src/generated/model/RenderStylesheetSerializer"; import { MasterBar } from "@src/model/MasterBar"; import { Track } from "@src/model/Track"; export class ScoreSerializer { - public static fromJson(obj: Score, r: IJsonReader): void { + public static fromJson(obj: Score, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -23,7 +23,7 @@ export class ScoreSerializer { } r.endObject(); } - public static toJson(obj: Score | null, w: IJsonWriter): void { + public static toJson(obj: Score | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -57,7 +57,7 @@ export class ScoreSerializer { RenderStylesheetSerializer.toJson(obj.stylesheet, w); w.endObject(); } - public static setProperty(obj: Score, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Score, property: string, r: JsonReader): boolean { switch (property) { case "album": obj.album = (r.string()!); diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts index 732cce82a..3ca086c7e 100644 --- a/src/generated/model/SectionSerializer.ts +++ b/src/generated/model/SectionSerializer.ts @@ -4,11 +4,11 @@ // the code is regenerated. // import { Section } from "@src/model/Section"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; export class SectionSerializer { - public static fromJson(obj: Section, r: IJsonReader): void { + public static fromJson(obj: Section, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -18,7 +18,7 @@ export class SectionSerializer { } r.endObject(); } - public static toJson(obj: Section | null, w: IJsonWriter): void { + public static toJson(obj: Section | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -28,7 +28,7 @@ export class SectionSerializer { w.string(obj.text, "text"); w.endObject(); } - public static setProperty(obj: Section, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Section, property: string, r: JsonReader): boolean { switch (property) { case "marker": obj.marker = (r.string()!); diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 53bc6acb5..6742af864 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -4,15 +4,15 @@ // the code is regenerated. // import { Staff } from "@src/model/Staff"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { BarSerializer } from "@src/generated/model/BarSerializer"; import { ChordSerializer } from "@src/generated/model/ChordSerializer"; import { Bar } from "@src/model/Bar"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { - public static fromJson(obj: Staff, r: IJsonReader): void { + public static fromJson(obj: Staff, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -22,7 +22,7 @@ export class StaffSerializer { } r.endObject(); } - public static toJson(obj: Staff | null, w: IJsonWriter): void { + public static toJson(obj: Staff | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -50,7 +50,7 @@ export class StaffSerializer { w.number(obj.standardNotationLineCount, "standardNotationLineCount"); w.endObject(); } - public static setProperty(obj: Staff, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Staff, property: string, r: JsonReader): boolean { switch (property) { case "index": obj.index = (r.number()!); diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index f5808088d..1e160a097 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -4,9 +4,9 @@ // the code is regenerated. // import { Track } from "@src/model/Track"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { StaffSerializer } from "@src/generated/model/StaffSerializer"; import { PlaybackInformationSerializer } from "@src/generated/model/PlaybackInformationSerializer"; import { Color } from "@src/model/Color"; @@ -14,7 +14,7 @@ import { InstrumentArticulationSerializer } from "@src/generated/model/Instrumen import { Staff } from "@src/model/Staff"; import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; export class TrackSerializer { - public static fromJson(obj: Track, r: IJsonReader): void { + public static fromJson(obj: Track, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -24,7 +24,7 @@ export class TrackSerializer { } r.endObject(); } - public static toJson(obj: Track | null, w: IJsonWriter): void { + public static toJson(obj: Track | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -51,7 +51,7 @@ export class TrackSerializer { w.endArray(); w.endObject(); } - public static setProperty(obj: Track, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Track, property: string, r: JsonReader): boolean { switch (property) { case "index": obj.index = (r.number()!); diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index 133cbe0bc..f04692e20 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -4,13 +4,13 @@ // the code is regenerated. // import { Voice } from "@src/model/Voice"; -import { IJsonReader } from "@src/io/IJsonReader"; -import { JsonValueType } from "@src/io/IJsonReader"; -import { IJsonWriter } from "@src/io/IJsonWriter"; +import { JsonReader } from "@src/io/JsonReader"; +import { JsonValueType } from "@src/io/JsonReader"; +import { JsonWriter } from "@src/io/JsonWriter"; import { BeatSerializer } from "@src/generated/model/BeatSerializer"; import { Beat } from "@src/model/Beat"; export class VoiceSerializer { - public static fromJson(obj: Voice, r: IJsonReader): void { + public static fromJson(obj: Voice, r: JsonReader): void { if (r.currentValueType === JsonValueType.Null) { return; } @@ -20,7 +20,7 @@ export class VoiceSerializer { } r.endObject(); } - public static toJson(obj: Voice | null, w: IJsonWriter): void { + public static toJson(obj: Voice | null, w: JsonWriter): void { if (!obj) { w.null(); return; @@ -36,7 +36,7 @@ export class VoiceSerializer { w.boolean(obj.isEmpty, "isEmpty"); w.endObject(); } - public static setProperty(obj: Voice, property: string, r: IJsonReader): boolean { + public static setProperty(obj: Voice, property: string, r: JsonReader): boolean { switch (property) { case "index": obj.index = (r.number()!); diff --git a/src/io/IJsonReader.ts b/src/io/IJsonReader.ts deleted file mode 100644 index 3f876703c..000000000 --- a/src/io/IJsonReader.ts +++ /dev/null @@ -1,229 +0,0 @@ -export enum JsonValueType { - String, - Number, - Boolean, - Null, - Object, - Array -} - -export interface IJsonReader { - readonly currentValueType: JsonValueType; - - startObject(): void; - endObject(): void; - - startArray(): void; - endArray(): void; - - prop(): string; - enumProp(enumType: unknown): T; - numberProp(): number; - - nextProp(): boolean; - nextItem(): boolean; - - unknown(): unknown; - string(): string | null; - enum(enumType: any): T | null; - number(): number | null; - boolean(): boolean | null; - - stringArray(): string[] | null; - numberArray(): number[] | null; -} - -/** - * @target web - */ -interface ReaderStackItem { - obj: any; - currentIndex: number; - - // for object iteration - currentProp?: string; - currentValue?: any; - - currentObjectKeys: string[]; -} - -/** - * @target web - */ -export class JsonObjectReader implements IJsonReader { - private _currentItem: ReaderStackItem | null = null; - private _readStack: ReaderStackItem[] = []; - - public currentValueType: JsonValueType = JsonValueType.Null; - - public constructor(root: any) { - root = { - root: root - }; - this.setCurrentObject(root); - this.nextProp(); - } - - private updateCurrentValueType(val: any) { - switch (typeof val) { - case 'undefined': - this.currentValueType = JsonValueType.Null; - break; - case 'string': - this.currentValueType = JsonValueType.String; - break; - case 'object': - if (val === null) { - this.currentValueType = JsonValueType.Null; - } else if (Array.isArray(val)) { - this.currentValueType = JsonValueType.Array; - } else { - this.currentValueType = JsonValueType.Object; - } - break; - case 'number': - this.currentValueType = JsonValueType.Number; - break; - case 'boolean': - this.currentValueType = JsonValueType.Boolean; - break; - } - } - - private setCurrentObject(current: any) { - let currentObjectKeys: string[] = typeof current === 'object' && current !== null - ? Object.keys(current) - : []; - const obj = { - obj: current, - currentIndex: -1, - currentObjectKeys: currentObjectKeys - }; - this._readStack.push(obj); - this._currentItem = obj; - } - - public prop(): string { - return this._currentItem?.currentProp ?? ""; - } - - private parseEnum(value: string, enumType: any): T { - return enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] as any; - } - - public enumProp(enumType: unknown): T { - const prop = this.prop(); - const num = parseInt(prop); - return isNaN(num) - ? this.parseEnum(prop, enumType) - : num as any; - } - - public numberProp(): number { - const prop = this.prop(); - return parseInt(prop); - } - - public nextProp(): boolean { - const currentItem = this._currentItem!; - currentItem.currentIndex++; - if (currentItem.currentIndex < currentItem.currentObjectKeys.length) { - currentItem.currentProp = currentItem.currentObjectKeys[currentItem.currentIndex]; - currentItem.currentValue = currentItem.obj[currentItem.currentProp]; - this.updateCurrentValueType(currentItem.currentValue); - return true; - } else { - this.currentValueType = JsonValueType.Null; - return false; - } - } - - public nextItem(): boolean { - const currentItem = this._currentItem!; - currentItem.currentIndex++; - - if (Array.isArray(currentItem.obj) && - currentItem.currentIndex < currentItem.obj.length) { - currentItem.currentValue = currentItem.obj[currentItem.currentIndex]; - this.updateCurrentValueType(currentItem.currentValue); - return true; - } else { - return false; - } - } - - - public startObject(): void { - const currentItem = this._currentItem; - if (currentItem) { - switch (this.currentValueType) { - case JsonValueType.Object: - this.setCurrentObject(currentItem.currentValue!); - break; - case JsonValueType.Array: - this.setCurrentObject(currentItem.currentValue!); - break; - default: - throw new Error(`Cannot start object/array in the current item. item is a ${JsonValueType[this.currentValueType]}`); - } - } - } - - public endObject(): void { - this._readStack.pop(); - this._currentItem = this._readStack[this._readStack.length - 1]; - } - - public startArray(): void { - this.startObject(); - } - - public endArray(): void { - this.endObject(); - } - - public unknown(): unknown { - return this.value(this.currentValueType); - } - - public string(): string | null { - return this.value(JsonValueType.String); - } - - public enum(enumType: any): T | null { - const currentItem = this._currentItem; - if (currentItem) { - switch (this.currentValueType) { - case JsonValueType.String: - return this.parseEnum(currentItem.currentValue as string, enumType); - case JsonValueType.Number: - return currentItem.currentValue as any; - } - } - return null; - } - - public number(): number | null { - return this.value(JsonValueType.Number); - } - - public boolean(): boolean | null { - return this.value(JsonValueType.Boolean); - } - - public stringArray(): string[] | null { - return this.value(JsonValueType.Array); - } - - public numberArray(): number[] | null { - return this.value(JsonValueType.Array); - } - - private value(type: JsonValueType): T | null { - const currentItem = this._currentItem; - if (currentItem && this.currentValueType === type) { - return currentItem.currentValue as T; - } - return null; - } -} \ No newline at end of file diff --git a/src/io/JsonReader.ts b/src/io/JsonReader.ts new file mode 100644 index 000000000..3771b1cc9 --- /dev/null +++ b/src/io/JsonReader.ts @@ -0,0 +1,323 @@ +/** + * Lists the different data types JSON properties can have. + */ +export enum JsonValueType { + /** + * The json value is a simple string. + */ + String, + /** + * The json value is a number. + */ + Number, + /** + * The json value is a boolean. + */ + Boolean, + /** + * The json value is null. + */ + Null, + /** + * The json value is a nested object. + */ + Object, + /** + * The json value is a nested array. + */ + Array +} + +/** + * @partial + */ +class ReaderStackItem { + public obj: unknown; + public currentIndex: number = -1; + + // for object iteration + public currentProp: string = ''; + public currentValue: unknown = null; + + public currentObjectKeys: string[]; + + public constructor(obj: unknown) { + if (obj) { + if (Array.isArray(obj)) { + this.currentObjectKeys = []; + } else { + if (!(obj instanceof Map)) { + obj = ReaderStackItem.objectToMap(obj as object); + } + this.currentObjectKeys = Array.from((obj as Map).keys()); + } + } else { + this.currentObjectKeys = []; + } + + + this.obj = obj; + } + + /** + * @target web + */ + private static objectToMap(obj: object | null): Map { + return new Map(Object.entries(obj as any)) + } +} + +/** + * Represents a data reader to read data structures from a JSON-alike source structure. + * @partial + */ +export class JsonReader { + private _currentItem: ReaderStackItem | null = null; + private _readStack: ReaderStackItem[] = []; + + /** + * Gets the data type of the current item at which the reader is placed. + * This is usually either the current property of an object or the current item in an array. + */ + public currentValueType: JsonValueType = JsonValueType.Null; + + public constructor(root: any) { + const map = new Map(); + map.set("root", root); + this.setCurrentObject(map); + this.nextProp(); + } + + /** + * Reads the current object property name as string. + * Requires that an object is currently being read. + */ + public prop(): string { + return this._currentItem?.currentProp ?? ""; + } + + /** + * Reads the current object property name as enum value. + * This works for either number or string based keys. + * @param enumType The type of the enum which defines the values of T + */ + public enumProp(enumType: unknown): T { + const prop = this.prop(); + const num = parseInt(prop); + return isNaN(num) + ? this.parseEnum(prop, enumType) + : num as unknown as T; + } + + /** + * Reads the current object property as number value. + */ + public numberProp(): number { + const prop = this.prop(); + return parseInt(prop); + } + + /** + * Advances the reader to the next property within the currently read object. + */ + public nextProp(): boolean { + const currentItem = this._currentItem!; + currentItem.currentIndex++; + if (currentItem.currentIndex < currentItem.currentObjectKeys.length) { + currentItem.currentProp = currentItem.currentObjectKeys[currentItem.currentIndex]; + currentItem.currentValue = (currentItem.obj as Map).get(currentItem.currentProp); + this.updateCurrentValueType(currentItem.currentValue); + return true; + } else { + this.currentValueType = JsonValueType.Null; + return false; + } + } + + /** + * Advances the reader to the next item within the currently read array. + */ + public nextItem(): boolean { + const currentItem = this._currentItem!; + currentItem.currentIndex++; + + if (Array.isArray(currentItem.obj) && + currentItem.currentIndex < (currentItem.obj as any[]).length) { + currentItem.currentValue = (currentItem.obj as any[])[currentItem.currentIndex]; + this.updateCurrentValueType(currentItem.currentValue); + return true; + } else { + return false; + } + } + + /** + * Starts reading of a nested object. + */ + public startObject(): void { + const currentItem = this._currentItem; + if (currentItem) { + switch (this.currentValueType) { + case JsonValueType.Object: + this.setCurrentObject(currentItem.currentValue!); + break; + case JsonValueType.Array: + this.setCurrentObject(currentItem.currentValue!); + break; + default: + throw new Error(`Cannot start object/array in the current item. item is a ${JsonValueType[this.currentValueType]}`); + } + } + } + + /** + * Completes the reading of a nested object. + */ + public endObject(): void { + this._readStack.pop(); + this._currentItem = this._readStack[this._readStack.length - 1]; + } + + /** + * Starts the reading of a nested array. + */ + public startArray(): void { + this.startObject(); + } + + /** + * Completes the reading of a nested array. + */ + public endArray(): void { + this.endObject(); + } + + /** + * Reads the current property value as a raw unknown value without further parsing. + * @returns the current raw property value + */ + public unknown(): unknown { + return this.value(this.currentValueType); + } + + /** + * Reads the current property value as string. + * @returns the current property value if it is a string or null if it is a different type. + */ + public string(): string | null { + return this.value(JsonValueType.String); + } + + /** + * Reads the current property value as enum. + * Number and case-insenstive strings are supported. + * @returns the current property value as enum or null if it could not be parsed. + */ + public enum(enumType: any): T | null { + const currentItem = this._currentItem; + if (currentItem) { + switch (this.currentValueType) { + case JsonValueType.String: + return this.parseEnum(currentItem.currentValue as string, enumType); + case JsonValueType.Number: + return this.numberToEnum(currentItem.currentValue as number); + } + } + return null; + } + + /** + * Reads the current property value as number. + * @returns the current property value if it is a number or null if it is a different type. + */ + public number(): number | null { + return this.valueStruct(JsonValueType.Number); + } + + /** + * Reads the current property value as boolean. + * @returns the current property value if it is a boolean or null if it is a different type. + */ + public boolean(): boolean | null { + return this.valueStruct(JsonValueType.Boolean); + } + + /** + * Reads the current property value as string array. + * @returns the current property value if it is an array or null if it is a different type. + */ + public stringArray(): string[] | null { + return this.value(JsonValueType.Array); + } + + /** + * Reads the current property value as number array. + * @returns the current property value if it is an array or null if it is a different type. + */ + public numberArray(): number[] | null { + return this.value(JsonValueType.Array); + } + + private updateCurrentValueType(val: any) { + switch (typeof val) { + case 'undefined': + this.currentValueType = JsonValueType.Null; + break; + case 'string': + this.currentValueType = JsonValueType.String; + break; + case 'object': + if (val === null) { + this.currentValueType = JsonValueType.Null; + } else if (Array.isArray(val)) { + this.currentValueType = JsonValueType.Array; + } else { + this.currentValueType = JsonValueType.Object; + } + break; + case 'number': + this.currentValueType = JsonValueType.Number; + break; + case 'boolean': + this.currentValueType = JsonValueType.Boolean; + break; + } + } + + private setCurrentObject(current: any) { + const obj = new ReaderStackItem(current); + this._readStack.push(obj); + this._currentItem = obj; + } + + // required for C# generation where nullable struct/classes need separate methods + private valueStruct(type: JsonValueType): T | null { + const currentItem = this._currentItem; + if (currentItem && this.currentValueType === type) { + return currentItem.currentValue as T; + } + return null; + } + + private value(type: JsonValueType): T | null { + const currentItem = this._currentItem; + if (currentItem && this.currentValueType === type) { + return currentItem.currentValue as T; + } + return null; + } + + /** + * @target web + */ + private parseEnum(value: string, enumType: any): T { + return enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] as any; + } + + /** + * @target web + */ + private numberToEnum(value: number): T { + return value as unknown as T; + } +} \ No newline at end of file diff --git a/src/io/IJsonWriter.ts b/src/io/JsonWriter.ts similarity index 61% rename from src/io/IJsonWriter.ts rename to src/io/JsonWriter.ts index fb7d07443..7223aea10 100644 --- a/src/io/IJsonWriter.ts +++ b/src/io/JsonWriter.ts @@ -1,46 +1,29 @@ -export interface IJsonWriter { - readonly result: unknown; - - startObject(): void; - endObject(): void; - - startArray(): void; - endArray(): void; - - prop(name: unknown): void; - - unknown(value: unknown, propName?: unknown): void; - string(value: string | null, propName?: unknown): void; - number(value: number | null, propName?: unknown): void; - boolean(value: boolean | null, propName?: unknown): void; - enum(value: T, propName?: unknown): void; - null(propName?: unknown): void; - stringArray(value: string[] | null, propName?: unknown): void; - numberArray(value: number[] | null, propName?: unknown): void; -} +import { AlphaTabError } from "@src/alphatab"; +import { AlphaTabErrorType } from "@src/AlphaTabError"; /** - * @target web + * Represents a data writer to write data structures into a JSON-alike object hierarchy for further serialization. + * @partial */ -export class JsonObjectWriter implements IJsonWriter { - private _objectStack: any[] = []; +export class JsonWriter { + private _objectStack: unknown[] = []; private _currentPropertyName: string = ''; - public result: unknown = null; + public result: Map | null = null; public startObject(): void { if (this._objectStack.length > 0) { - const newObject: any = {}; + const newObject = new Map(); const currentObject = this._objectStack[this._objectStack.length - 1]; this._objectStack.push(newObject); if (Array.isArray(currentObject)) { currentObject.push(newObject); } else { - currentObject[this._currentPropertyName] = newObject; + (currentObject as Map).set(this._currentPropertyName, newObject); } } else { - this.result = {}; + this.result = new Map(); this._objectStack.push(this.result); } } @@ -51,18 +34,17 @@ export class JsonObjectWriter implements IJsonWriter { public startArray(): void { if (this._objectStack.length > 0) { - const newObject: any = []; + const newObject: unknown[] = []; const currentObject = this._objectStack[this._objectStack.length - 1]; this._objectStack.push(newObject); if (Array.isArray(currentObject)) { currentObject.push(newObject); } else { - currentObject[this._currentPropertyName] = newObject; + (currentObject as Map).set(this._currentPropertyName, newObject); } } else { - this.result = []; - this._objectStack.push(this.result); + throw new AlphaTabError(AlphaTabErrorType.General, 'Root object to be serialized cannot be an array'); } } @@ -71,7 +53,7 @@ export class JsonObjectWriter implements IJsonWriter { } public prop(name: unknown): void { - this._currentPropertyName = name as any; + this._currentPropertyName = (name as object).toString(); } public unknown(value: unknown, propName?: unknown): void { @@ -91,7 +73,7 @@ export class JsonObjectWriter implements IJsonWriter { } public enum(value: T, propName?: unknown): void { - this.writeValue(value, propName); + this.writeValue(this.enumToNumber(value), propName); } public null(propName?: unknown): void { @@ -111,13 +93,21 @@ export class JsonObjectWriter implements IJsonWriter { const currentObject = this._objectStack[this._objectStack.length - 1]; if (Array.isArray(currentObject)) { this._objectStack.push(value); - } else if (typeof propName !== 'undefined') { - currentObject[propName as any] = value; } else { - currentObject[this._currentPropertyName] = value; + if (typeof propName === 'undefined') { + propName = this._currentPropertyName; + } + (currentObject as Map).set((propName as object).toString(), value); } } else { - this.result = value; + throw new AlphaTabError(AlphaTabErrorType.General, 'Root object to be serialized cannot be a plain value'); } } + + /** + * @target web + */ + private enumToNumber(value: T): number | null { + return value as unknown as number; + } } \ No newline at end of file diff --git a/src/model/Color.ts b/src/model/Color.ts index e6c92a131..73cbb535e 100644 --- a/src/model/Color.ts +++ b/src/model/Color.ts @@ -1,6 +1,6 @@ import { FormatError } from '@src/FormatError'; -import { IJsonReader, JsonValueType } from '@src/io/IJsonReader'; -import { IJsonWriter } from '@src/io/IJsonWriter'; +import { JsonReader, JsonValueType } from '@src/io/JsonReader'; +import { JsonWriter } from '@src/io/JsonWriter'; import { ModelUtils } from './ModelUtils'; /** @@ -64,7 +64,7 @@ export class Color { return new Color((Math.random() * 255) | 0, (Math.random() * 255) | 0, (Math.random() * 255) | 0, opacity); } - public static fromJson(reader: IJsonReader): Color | null { + public static fromJson(reader: JsonReader): Color | null { switch (reader.currentValueType) { case JsonValueType.Number: { @@ -142,7 +142,7 @@ export class Color { throw new FormatError('Unsupported format for color'); } - public static toJson(obj: Color, writer: IJsonWriter): void { + public static toJson(obj: Color, writer: JsonWriter): void { writer.number(obj.raw); } } diff --git a/src/model/Font.ts b/src/model/Font.ts index 237f5788a..2571cfd4f 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -1,5 +1,5 @@ -import { IJsonReader, JsonValueType } from '@src/io/IJsonReader'; -import { IJsonWriter } from '@src/io/IJsonWriter'; +import { JsonReader, JsonValueType } from '@src/io/JsonReader'; +import { JsonWriter } from '@src/io/JsonWriter'; /** * A very basic font parser which parses the fields according to @@ -339,7 +339,7 @@ export class Font { return this._css; } - public static fromJson(reader: IJsonReader): Font | null { + public static fromJson(reader: JsonReader): Font | null { switch (reader.currentValueType) { case JsonValueType.Null: return null; @@ -348,6 +348,7 @@ export class Font { let family = ''; let size = 0; let style = FontStyle.Plain; + reader.startObject(); while (reader.nextProp()) { switch (reader.prop().toLowerCase()) { case 'family': @@ -361,6 +362,7 @@ export class Font { break; } } + reader.endObject(); return new Font(family, size, style); } case JsonValueType.String: @@ -438,14 +440,11 @@ export class Font { } } - public static toJson(font: Font, writer: IJsonWriter): void { + public static toJson(font: Font, writer: JsonWriter): void { writer.startObject(); - writer.prop('family'); - writer.string(font.family); - writer.prop('size'); - writer.number(font.size); - writer.prop('style'); - writer.enum(font.style); + writer.string(font.family, 'family'); + writer.number(font.size, 'size'); + writer.number(font.style, 'style'); writer.endObject(); } } diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 307f2cc06..c9197c7ca 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -7,8 +7,9 @@ import { Score } from '@src/model/Score'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; import { ScoreSerializer } from '@src/generated/model/ScoreSerializer'; -import { JsonObjectReader } from '@src/io/IJsonReader'; -import { JsonObjectWriter } from '@src/io/IJsonWriter'; +import { JsonReader } from '@src/io/JsonReader'; +import { JsonWriter } from '@src/io/JsonWriter'; +import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * This class can convert a full {@link Score} instance to a simple JavaScript object and back for further @@ -38,7 +39,7 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - const writer = new JsonObjectWriter(); + const writer = new JsonWriter(); ScoreSerializer.toJson(score, writer); return writer.result; } @@ -57,16 +58,38 @@ export class JsonConverter { /** * Converts the given JavaScript object into a score object. * @param jsObject The javascript object created via {@link Score} - * @pas The settings to use during conversion. + * @param settings The settings to use during conversion. * @returns The converted score object. */ public static jsObjectToScore(jsObject: any, settings?: Settings): Score { let score: Score = new Score(); - ScoreSerializer.fromJson(score, new JsonObjectReader(jsObject)); + ScoreSerializer.fromJson(score, new JsonReader(jsObject)); score.finish(settings ?? new Settings()); return score; } + /** + * Converts the settings object into a JavaScript object for transmission between components or saving purposes. + * @param settings The settings object to serialize + * @returns A serialized settings object without ciruclar dependencies that can be used for further serializations. + */ + public static settingsToJsObject(settings: Settings): unknown { + const writer = new JsonWriter(); + SettingsSerializer.toJson(settings, writer); + return writer.result; + } + + /** + * Converts the given JavaScript object into a settings object. + * @param jsObject The javascript object created via {@link Settings} + * @returns The converted Settings object. + */ + public static jsObjectToSettings(jsObject: any): Settings { + let settings: Settings = new Settings(); + SettingsSerializer.fromJson(settings, new JsonReader(jsObject)); + return settings; + } + /** * @target web */ diff --git a/src/platform/javascript/AlphaTabWebWorker.ts b/src/platform/javascript/AlphaTabWebWorker.ts index 3dfb294d1..14e8f0493 100644 --- a/src/platform/javascript/AlphaTabWebWorker.ts +++ b/src/platform/javascript/AlphaTabWebWorker.ts @@ -6,7 +6,7 @@ import { ScoreRenderer } from '@src/rendering/ScoreRenderer'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { Environment } from '@src/Environment'; -import { JsonObjectReader } from '@src/io/IJsonReader'; +import { JsonReader } from '@src/io/JsonReader'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** @@ -30,8 +30,7 @@ export class AlphaTabWebWorker { let cmd: any = data ? data.cmd : ''; switch (cmd) { case 'alphaTab.initialize': - let settings: Settings = new Settings(); - SettingsSerializer.fromJson(settings, new JsonObjectReader(data.settings)); + let settings: Settings = JsonConverter.jsObjectToSettings(data.settings); new Settings(); Logger.logLevel = settings.core.logLevel; this._renderer = new ScoreRenderer(settings); this._renderer.partialRenderFinished.on(result => { @@ -92,7 +91,7 @@ export class AlphaTabWebWorker { } private updateSettings(json: unknown): void { - SettingsSerializer.fromJson(this._renderer.settings, new JsonObjectReader(json)); + SettingsSerializer.fromJson(this._renderer.settings, new JsonReader(json)); } private renderMultiple(score: Score, trackIndexes: number[]): void { diff --git a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts index 71060f048..6ceb5da9d 100644 --- a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts +++ b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts @@ -8,8 +8,6 @@ import { RenderFinishedEventArgs } from '@src/rendering/RenderFinishedEventArgs' import { BoundsLookup } from '@src/rendering/utils/BoundsLookup'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; -import { JsonObjectWriter } from '@src/io/IJsonWriter'; -import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * @target web @@ -61,12 +59,10 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { } private serializeSettingsForWorker(settings: Settings): unknown { - const writer = new JsonObjectWriter(); - SettingsSerializer.toJson(settings, writer); + const jsObject = JsonConverter.settingsToJsObject(settings); // cut out player settings, they are only needed on UI thread side - const json: any = writer.result; - json.player = null; - return json; + delete (jsObject as any).player; + return jsObject; } public render(): void { diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index ec906afa5..a62e983b5 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -23,8 +23,7 @@ import { AlphaTabApi } from '@src/platform/javascript/AlphaTabApi'; import { AlphaTabWorkerScoreRenderer } from '@src/platform/javascript/AlphaTabWorkerScoreRenderer'; import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; import { Cursors } from '@src/platform/Cursors'; -import { JsonObjectReader } from '@src/io/IJsonReader'; -import { SettingsSerializer } from '@src/generated/SettingsSerializer'; +import { JsonConverter } from '@src/model/JsonConverter'; /** * @target web @@ -123,8 +122,7 @@ export class BrowserUiFacade implements IUiFacade { if (raw instanceof Settings) { settings = raw; } else { - settings = new Settings(); - SettingsSerializer.fromJson(settings, new JsonObjectReader(raw)); + settings = JsonConverter.jsObjectToSettings(raw); } let dataAttributes: Map = this.getDataAttributes(); diff --git a/src/rendering/TabBarRenderer.ts b/src/rendering/TabBarRenderer.ts index 9906ea154..b8f900126 100644 --- a/src/rendering/TabBarRenderer.ts +++ b/src/rendering/TabBarRenderer.ts @@ -33,7 +33,7 @@ import { ModelUtils } from '@src/model/ModelUtils'; */ export class TabBarRenderer extends BarRendererBase { public static readonly StaffId: string = 'tab'; - public static readonly LineSpacing: number = 10; + public static readonly TabLineSpacing: number = 10; private _tupletSize: number = 0; @@ -46,7 +46,7 @@ export class TabBarRenderer extends BarRendererBase { } public get lineOffset(): number { - return (TabBarRenderer.LineSpacing + 1) * this.scale; + return (TabBarRenderer.TabLineSpacing + 1) * this.scale; } protected updateSizes(): void { diff --git a/test/model/Font.test.ts b/test/model/Font.test.ts index e70591f9c..99b859847 100644 --- a/test/model/Font.test.ts +++ b/test/model/Font.test.ts @@ -1,9 +1,9 @@ -import { JsonObjectReader } from "@src/io/IJsonReader"; +import { JsonReader } from "@src/io/JsonReader"; import { Font, FontStyle } from "@src/model/Font"; describe('FontTests', () => { function parseText(text: string, expected: Font) { - const reader = new JsonObjectReader(text); + const reader = new JsonReader(text); const font = Font.fromJson(reader); expect(font!.family).toEqual(expected.family); expect(font!.isBold).toEqual(expected.isBold); diff --git a/test/model/JsonConverter.test.ts b/test/model/JsonConverter.test.ts index 1dcb64e49..518e4ed39 100644 --- a/test/model/JsonConverter.test.ts +++ b/test/model/JsonConverter.test.ts @@ -1,6 +1,12 @@ +import { FingeringMode, LayoutMode, LogLevel, NotationMode, Settings, StaveProfile } from "@src/alphatab"; +import { SettingsSerializer } from "@src/generated/SettingsSerializer"; import { ScoreLoader } from "@src/importer/ScoreLoader"; +import { JsonReader } from "@src/io/JsonReader"; +import { Color } from "@src/model/Color"; +import { Font, FontStyle } from "@src/model/Font"; import { JsonConverter } from "@src/model/JsonConverter"; import { Score } from "@src/model/Score"; +import { NotationElement, TabRhythmMode } from "@src/NotationSettings"; import { TestPlatform } from "@test/TestPlatform"; describe('JsonConverterTest', () => { @@ -14,7 +20,7 @@ describe('JsonConverterTest', () => { } }; - function expectJsonEqual(expected: any, actual: any, path: string) { + function expectJsonEqual(expected: unknown, actual: unknown, path: string) { const expectedType = typeof expected; const actualType = typeof actual; @@ -50,34 +56,42 @@ describe('JsonConverterTest', () => { expectJsonEqual(expected[i], actual[i], `${path}[${i}]`); } } - } else if(!Array.isArray(actual)) { + } else if (expected instanceof Map) { + if (!(actual instanceof Map)) { + fail(`Map mismatch on hierarchy: ${path}, '${actual}' != '${expected}'`); + } else { + const expectedMap = expected as Map; + const actualMap = actual as Map; - const expectedKeys = Object.keys(expected); - const actualKeys = Object.keys(actual); - expectedKeys.sort(); - actualKeys.sort(); + const expectedKeys = Array.from(expectedMap.keys()); + const actualKeys = Array.from(actualMap.keys()); + expectedKeys.sort(); + actualKeys.sort(); - const actualKeyList = actualKeys.join(','); - const expectedKeyList = expectedKeys.join(','); - if (actualKeyList !== expectedKeyList) { - fail(`Object Keys mismatch on hierarchy: ${path}, '${actualKeyList}' != '${expectedKeyList}'`); - } else { - for (const key of actualKeys) { - switch (key) { - // some ignored keys - case 'id': - case 'hammerPullOriginId': - case 'hammerPullDestinationId': - case 'tieOriginId': - case 'tieDestinationId': - break; - default: - expectJsonEqual(expected[key], actual[key], `${path}.${key}`); - break; + const actualKeyList = actualKeys.join(','); + const expectedKeyList = expectedKeys.join(','); + if (actualKeyList !== expectedKeyList) { + fail(`Object Keys mismatch on hierarchy: ${path}, '${actualKeyList}' != '${expectedKeyList}'`); + } else { + for (const key of actualKeys) { + switch (key) { + // some ignored keys + case 'id': + case 'hammerPullOriginId': + case 'hammerPullDestinationId': + case 'tieOriginId': + case 'tieDestinationId': + break; + default: + expectJsonEqual(expectedMap.get(key), actualMap.get(key), `${path}.${key}`); + break; + } } - } + } } + } else { + fail('Need Map serialization for comparing json objects'); } } break; @@ -153,4 +167,129 @@ describe('JsonConverterTest', () => { it('visual-special-tracks', async () => { await testRoundTripFolderEqual('visual-tests/special-tracks'); }); + + + it('settings', () => { + const expected = new Settings(); + // here we modifiy some properties of each level and some special ones additionally + // to ensure all properties are considered properly + + /**@target web*/ + expected.core.scriptFile = 'script'; + /**@target web*/ + expected.core.fontDirectory = 'font'; + /**@target web*/ + expected.core.tex = true; + /**@target web*/ + expected.core.tracks = [1, 2, 3]; + /**@target web*/ + expected.core.visibilityCheckInterval = 4711; + + expected.core.enableLazyLoading = false; + expected.core.engine = "engine"; + expected.core.logLevel = LogLevel.Error; + expected.core.useWorkers = false; + expected.core.includeNoteBounds = true; + + expected.display.scale = 10; + expected.display.stretchForce = 2; + expected.display.staveProfile = StaveProfile.ScoreTab; + expected.display.barCountPerPartial = 14; + expected.display.resources.copyrightFont = new Font('copy', 15, FontStyle.Plain); + expected.display.resources.staffLineColor = new Color(255, 0, 0, 100); + expected.display.padding = [1, 2, 3, 4]; + + expected.notation.notationMode = NotationMode.SongBook; + expected.notation.fingeringMode = FingeringMode.ScoreForcePiano; + expected.notation.elements.set(NotationElement.EffectCapo, false); + expected.notation.elements.set(NotationElement.ZerosOnDiveWhammys, true); + expected.notation.rhythmMode = TabRhythmMode.ShowWithBars; + expected.notation.rhythmHeight = 100; + expected.notation.transpositionPitches = [1, 2, 3, 4]; + expected.notation.displayTranspositionPitches = [5, 6, 7, 8]; + expected.notation.extendBendArrowsOnTiedNotes = false; + expected.notation.extendLineEffectsToBeatEnd = true; + expected.notation.slurHeight = 50; + + expected.importer.encoding = 'enc'; + expected.importer.mergePartGroupsInMusicXml = false; + + expected.player.soundFont = 'soundfont'; + expected.player.scrollElement = 'scroll'; + expected.player.vibrato.noteSlightAmplitude = 10; + expected.player.slide.simpleSlideDurationRatio = 8; + + const expectedJson = JsonConverter.settingsToJsObject(expected); + const actual = JsonConverter.jsObjectToSettings(expectedJson); + const actualJson = JsonConverter.settingsToJsObject(actual); + + expectJsonEqual(expectedJson, actualJson, ''); + }); + + it('settings-from-map', () => { + const settings = new Settings(); + + const raw = new Map(); + + // json_on_parent + raw.set('enableLazyLoading', false); + // string enum + raw.set('logLevel', 'error'); + raw.set('displayLayoutMode', 1.0); + + // nested + const display = new Map(); + display.set('scale', 5.0); + raw.set('display', display); + + // json_partial_names + raw.set('notationRhythmMode', 'sHoWWITHbArs'); + + // immutable + raw.set('displayResourcesCopyrightFont', 'italic 18px Roboto'); + + SettingsSerializer.fromJson(settings, new JsonReader(raw)); + + expect(settings.core.enableLazyLoading).toEqual(false); + expect(settings.core.logLevel).toEqual(LogLevel.Error); + expect(settings.display.layoutMode).toEqual(LayoutMode.Horizontal); + expect(settings.display.scale).toEqual(5); + expect(settings.notation.rhythmMode).toEqual(TabRhythmMode.ShowWithBars); + expect(settings.display.resources.copyrightFont.family).toEqual('Roboto'); + expect(settings.display.resources.copyrightFont.size).toEqual(18); + expect(settings.display.resources.copyrightFont.style).toEqual(FontStyle.Italic); + }); + + + /*@target web*/ + it('settings-from-object', () => { + const settings = new Settings(); + + const raw = { + // json_on_parent + enableLazyLoading: false, + // string enum + logLevel: 'error', + displayLayoutMode: 1.0, + // nested + display: { + scale: 5.0 + }, + // json_partial_names + notationRhythmMode: 'sHoWWITHbArs', + // immutable + displayResourcesCopyrightFont: 'italic 18px Roboto' + }; + + SettingsSerializer.fromJson(settings, new JsonReader(raw)); + + expect(settings.core.enableLazyLoading).toEqual(false); + expect(settings.core.logLevel).toEqual(LogLevel.Error); + expect(settings.display.layoutMode).toEqual(LayoutMode.Horizontal); + expect(settings.display.scale).toEqual(5); + expect(settings.notation.rhythmMode).toEqual(TabRhythmMode.ShowWithBars); + expect(settings.display.resources.copyrightFont.family).toEqual('Roboto'); + expect(settings.display.resources.copyrightFont.size).toEqual(18); + expect(settings.display.resources.copyrightFont.style).toEqual(FontStyle.Italic); + }); }); From 087734fced82ce56c857f673f737b604c8fb71ec Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Thu, 24 Dec 2020 18:43:17 +0100 Subject: [PATCH 15/19] Cleanup --- src.compiler/typescript/SerializerEmitter.ts | 3 +- src/Settings.ts | 8 ++--- src/generated/PlayerSettingsSerializer.ts | 32 ++++++++++++++++++++ src/model/Beat.ts | 2 ++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index abdc39891..f3dac6779 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -1104,8 +1104,7 @@ export default createEmitter('json', (program, input) => { const propertyDeclaration = member as ts.PropertyDeclaration; if (!propertyDeclaration.modifiers!.find(m => m.kind === ts.SyntaxKind.StaticKeyword || - m.kind === ts.SyntaxKind.PrivateKeyword || - m.kind === ts.SyntaxKind.ReadonlyKeyword)) { + m.kind === ts.SyntaxKind.PrivateKeyword)) { const jsonNames = [(member.name as ts.Identifier).text]; if (ts.getJSDocTags(member).find(t => t.tagName.text === 'json_on_parent')) { diff --git a/src/Settings.ts b/src/Settings.ts index 27ed5d7d8..88faab58d 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -26,26 +26,26 @@ export class Settings { * @json_on_parent * @json_partial_names */ - public core: CoreSettings = new CoreSettings(); + public readonly core: CoreSettings = new CoreSettings(); /** * The display settings control how the general layout and display of alphaTab is done. * @json_on_parent * @json_partial_names */ - public display: DisplaySettings = new DisplaySettings(); + public readonly display: DisplaySettings = new DisplaySettings(); /** * The notation settings control how various music notation elements are shown and behaving. * @json_partial_names */ - public notation: NotationSettings = new NotationSettings(); + public readonly notation: NotationSettings = new NotationSettings(); /** * All settings related to importers that decode file formats. * @json_partial_names */ - public importer: ImporterSettings = new ImporterSettings(); + public readonly importer: ImporterSettings = new ImporterSettings(); /** * Contains all player related settings diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index 4d9fcb0a6..9dd9a850a 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -7,6 +7,8 @@ import { PlayerSettings } from "@src/PlayerSettings"; import { JsonReader } from "@src/io/JsonReader"; import { JsonValueType } from "@src/io/JsonReader"; import { JsonWriter } from "@src/io/JsonWriter"; +import { VibratoPlaybackSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; +import { SlidePlaybackSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { public static fromJson(obj: PlayerSettings, r: JsonReader): void { @@ -36,6 +38,10 @@ export class PlayerSettingsSerializer { w.number(obj.scrollSpeed, "scrollSpeed"); w.number(obj.songBookBendDuration, "songBookBendDuration"); w.number(obj.songBookDipDuration, "songBookDipDuration"); + w.prop("vibrato"); + VibratoPlaybackSettingsSerializer.toJson(obj.vibrato, w); + w.prop("slide"); + SlidePlaybackSettingsSerializer.toJson(obj.slide, w); w.boolean(obj.playTripletFeel, "playTripletFeel"); w.endObject(); } @@ -78,6 +84,32 @@ export class PlayerSettingsSerializer { obj.playTripletFeel = (r.boolean()!); return true; } + if (["vibrato"].indexOf(property) >= 0) { + VibratoPlaybackSettingsSerializer.fromJson(obj.vibrato, r); + return true; + } + else { + for (const c of ["vibrato"]) { + if (property.indexOf(c) === 0) { + if (VibratoPlaybackSettingsSerializer.setProperty(obj.vibrato, property.substring(c.length), r)) { + return true; + } + } + } + } + if (["slide"].indexOf(property) >= 0) { + SlidePlaybackSettingsSerializer.fromJson(obj.slide, r); + return true; + } + else { + for (const c of ["slide"]) { + if (property.indexOf(c) === 0) { + if (SlidePlaybackSettingsSerializer.setProperty(obj.slide, property.substring(c.length), r)) { + return true; + } + } + } + } return false; } } diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 5b2104a7d..407095c6f 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -96,12 +96,14 @@ export class Beat { /** * Gets the lookup where the notes per string are registered. * If this staff contains string based notes this lookup allows fast access. + * @json_ignore */ public readonly noteStringLookup: Map = new Map(); /** * Gets the lookup where the notes per value are registered. * If this staff contains string based notes this lookup allows fast access. + * @json_ignore */ public readonly noteValueLookup: Map = new Map(); From e731f45609e233f5596f0a323904b44317685034 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 27 Dec 2020 16:09:32 +0100 Subject: [PATCH 16/19] Rework serialzier to basic map for better performance --- src.compiler/typescript/SerializerEmitter.ts | 732 +++++++++--------- src.csharp/AlphaTab/AlphaTab.csproj | 1 - src.csharp/AlphaTab/Core/EcmaScript/Array.cs | 5 - src.csharp/AlphaTab/Core/EcmaScript/Object.cs | 23 - src.csharp/AlphaTab/IO/JsonReader.cs | 17 - src.csharp/AlphaTab/IO/JsonWriter.cs | 17 - src.csharp/AlphaTab/IO/ObjectToMap.cs | 21 - src.csharp/AlphaTab/Io/JsonHelper.cs | 52 ++ src/Settings.ts | 11 - src/generated/CoreSettingsSerializer.ts | 69 +- src/generated/DisplaySettingsSerializer.ts | 68 +- src/generated/ImporterSettingsSerializer.ts | 33 +- src/generated/NotationSettingsSerializer.ts | 82 +- src/generated/PlayerSettingsSerializer.ts | 91 +-- src/generated/RenderingResourcesSerializer.ts | 110 +-- src/generated/SettingsSerializer.ts | 60 +- .../SlidePlaybackSettingsSerializer.ts | 37 +- .../VibratoPlaybackSettingsSerializer.ts | 57 +- src/generated/model/AutomationSerializer.ts | 45 +- src/generated/model/BarSerializer.ts | 58 +- src/generated/model/BeatSerializer.ts | 208 +++-- src/generated/model/BendPointSerializer.ts | 33 +- src/generated/model/ChordSerializer.ts | 53 +- src/generated/model/FermataSerializer.ts | 33 +- .../model/InstrumentArticulationSerializer.ts | 53 +- src/generated/model/MasterBarSerializer.ts | 120 ++- src/generated/model/NoteSerializer.ts | 206 +++-- .../model/PlaybackInformationSerializer.ts | 57 +- .../model/RenderStylesheetSerializer.ts | 29 +- src/generated/model/ScoreSerializer.ts | 104 +-- src/generated/model/SectionSerializer.ts | 33 +- src/generated/model/StaffSerializer.ts | 97 +-- src/generated/model/TrackSerializer.ts | 73 +- src/generated/model/VoiceSerializer.ts | 46 +- src/io/JsonHelper.ts | 40 + src/io/JsonReader.ts | 323 -------- src/io/JsonWriter.ts | 113 --- src/model/Color.ts | 18 +- src/model/Font.ts | 49 +- src/model/JsonConverter.ts | 20 +- src/platform/javascript/AlphaTabWebWorker.ts | 3 +- .../javascript/AlphaTabWorkerScoreRenderer.ts | 4 +- src/platform/javascript/BrowserUiFacade.ts | 3 +- test/model/Font.test.ts | 4 +- test/model/JsonConverter.test.ts | 9 +- 45 files changed, 1288 insertions(+), 2032 deletions(-) delete mode 100644 src.csharp/AlphaTab/Core/EcmaScript/Object.cs delete mode 100644 src.csharp/AlphaTab/IO/JsonReader.cs delete mode 100644 src.csharp/AlphaTab/IO/JsonWriter.cs delete mode 100644 src.csharp/AlphaTab/IO/ObjectToMap.cs create mode 100644 src.csharp/AlphaTab/Io/JsonHelper.cs create mode 100644 src/io/JsonHelper.ts delete mode 100644 src/io/JsonReader.ts delete mode 100644 src/io/JsonWriter.ts diff --git a/src.compiler/typescript/SerializerEmitter.ts b/src.compiler/typescript/SerializerEmitter.ts index f3dac6779..dadc27755 100644 --- a/src.compiler/typescript/SerializerEmitter.ts +++ b/src.compiler/typescript/SerializerEmitter.ts @@ -45,6 +45,15 @@ function toImportPath(fileName: string) { return "@" + removeExtension(fileName).split('\\').join('/'); } +function createStringUnknownMapNode(): ts.TypeNode { + return ts.factory.createTypeReferenceNode('Map', + [ + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword), + ]); +} + + function findModule(type: ts.Type, options: ts.CompilerOptions) { if (type.symbol) { for (const decl of type.symbol.declarations) { @@ -68,18 +77,19 @@ function findSerializerModule(type: ts.Type, options: ts.CompilerOptions) { let module = findModule(type, options); const importPath = module.split('/'); importPath.splice(1, 0, 'generated'); - return importPath.join('/') + 'Serializer'; + importPath[importPath.length - 1] = type.symbol!.name + 'Serializer'; + return importPath.join('/'); } // // fromJson -function generateFromJsonBody() { +function generateFromJsonBody(importer: (name: string, module: string) => void) { + importer('JsonHelper', '@src/io/JsonHelper'); return ts.factory.createBlock(addNewLines([ ts.factory.createIfStatement( - ts.factory.createBinaryExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'currentValueType'), - ts.SyntaxKind.EqualsEqualsEqualsToken, - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Null'), + ts.factory.createPrefixUnaryExpression( + ts.SyntaxKind.ExclamationToken, + ts.factory.createIdentifier('m'), ), ts.factory.createBlock([ ts.factory.createReturnStatement() @@ -87,47 +97,41 @@ function generateFromJsonBody() { ), ts.factory.createExpressionStatement( ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startObject'), - undefined, - [] - ) - ), - ts.factory.createWhileStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextProp'), + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('JsonHelper'), + 'forEach' + ), undefined, - [] - ), - ts.factory.createBlock([ - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'setProperty'), + [ + ts.factory.createIdentifier('m'), + ts.factory.createArrowFunction( + undefined, undefined, [ - ts.factory.createIdentifier('obj'), - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'prop'), - undefined, - [] + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'setProperty'), + undefined, + [ + ts.factory.createIdentifier('obj'), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('k'), + 'toLowerCase' ), - 'toLowerCase' + undefined, + [] ), - undefined, - [] - ), - ts.factory.createIdentifier('r'), - ] + ts.factory.createIdentifier('v'), + ] + ) + ) - ) - ]) - ), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endObject'), - undefined, - [] + ] ) ), ])); @@ -135,8 +139,6 @@ function generateFromJsonBody() { function createFromJsonMethod(input: ts.ClassDeclaration, importer: (name: string, module: string) => void) { - importer('JsonReader', '@src/io/JsonReader'); - importer('JsonValueType', '@src/io/JsonReader'); return ts.factory.createMethodDeclaration( undefined, [ @@ -163,52 +165,47 @@ function createFromJsonMethod(input: ts.ClassDeclaration, undefined, undefined, undefined, - 'r', + 'm', undefined, - ts.factory.createTypeReferenceNode('JsonReader') + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), - generateFromJsonBody() + generateFromJsonBody(importer) ) } - // // toJson -function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecker) { +function isPrimitiveToJson(type: ts.Type, typeChecker: ts.TypeChecker) { if (!type) { - return null; + return false; } const isArray = isTypedArray(type); const arrayItemType = unwrapArrayItemType(type, typeChecker); if (hasFlag(type, ts.TypeFlags.Unknown)) { - return "unknown"; + return true; } if (hasFlag(type, ts.TypeFlags.Number)) { - return "number"; + return true; } if (hasFlag(type, ts.TypeFlags.String)) { - return "string"; + return true; } if (hasFlag(type, ts.TypeFlags.Boolean)) { - return "boolean"; - } - - if (isEnumType(type)) { - return 'enum'; + return "val"; } if (arrayItemType) { if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { - return "numberArray"; + return true; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { - return "stringArray"; + return true; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { - return "booleanArray"; + return true; } } else if (type.symbol) { switch (type.symbol.name) { @@ -220,11 +217,11 @@ function getWriteMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeCheck case 'Int32Array': case 'Float32Array': case 'Float64Array': - return type.symbol.name.substring(0, 1).toLowerCase() + type.symbol.name.substring(1); + return true; } } - return null; + return false; } function generateToJsonBody( @@ -240,18 +237,28 @@ function generateToJsonBody( ts.factory.createIdentifier('obj') ), ts.factory.createBlock([ - ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'null'), - undefined, [] - )), - ts.factory.createReturnStatement() + ts.factory.createReturnStatement(ts.factory.createNull()) ]) )) - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startObject'), - undefined, [] - ))); + statements.push(ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList( + [ + ts.factory.createVariableDeclaration('o', + undefined, + undefined, + ts.factory.createNewExpression(ts.factory.createIdentifier('Map'), + [ + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword), + ], + [] + )) + ], + ts.NodeFlags.Const + ) + )); for (let prop of propertiesToSerialize) { const fieldName = (prop.property.name as ts.Identifier).text; @@ -264,205 +271,194 @@ function generateToJsonBody( const type = getTypeWithNullableInfo(typeChecker, prop.property.type!); const isArray = isTypedArray(type.type!); - let writeValueMethodName: string | null = getWriteMethodNameForPrimitive(type.type!, typeChecker); - let propertyStatements: ts.Statement[] = []; - if (writeValueMethodName) { + if (isPrimitiveToJson(type.type!, typeChecker)) { propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), writeValueMethodName), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), undefined, [ - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), ts.factory.createStringLiteral(jsonName), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), ] ))); - } else if (isArray) { - // NOTE: nullable Object arrays are not yet supported + } else if (isEnumType(type.type!)) { propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), undefined, [ - ts.factory.createStringLiteral(jsonName) + ts.factory.createStringLiteral(jsonName), + ts.factory.createAsExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + type.isNullable + ? ts.factory.createUnionTypeNode([ + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]) + : ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) + ) ] ))); - + } else if (isArray) { const arrayItemType = unwrapArrayItemType(type.type!, typeChecker)!; - let itemSerializer = arrayItemType.symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(arrayItemType, program.getCompilerOptions())); propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startArray'), - undefined, - [] - ))); - - propertyStatements.push(ts.factory.createForOfStatement( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), undefined, - ts.factory.createVariableDeclarationList( - [ts.factory.createVariableDeclaration('i')], - ts.NodeFlags.Const - ), - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createBlock([ - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - undefined, - [ - ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('w') - ] - ) + [ + ts.factory.createStringLiteral(jsonName), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + 'map' + ), + undefined, + [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'i')], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + undefined, + [ + ts.factory.createIdentifier('i'), + ] + ) + ) + ] ) - ]) - )); - - propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endArray'), - undefined, - [] + ] ))); } else if (isMap(type.type)) { - propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), - undefined, - [ - ts.factory.createStringLiteral(jsonName) - ] - ))); - const mapType = type.type as ts.TypeReference; if (!isPrimitiveType(mapType.typeArguments![0])) { throw new Error('only Map maps are supported extend if needed!'); } - let itemSerializer: string; let writeValue: ts.Expression; - if (isPrimitiveType(mapType.typeArguments![1])) { - itemSerializer = ''; - writeValue = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('w'), - getWriteMethodNameForPrimitive(mapType.typeArguments![1], typeChecker)! - ), - undefined, - [ts.factory.createIdentifier('v')] + if (isPrimitiveToJson(mapType.typeArguments![1], typeChecker)) { + writeValue = ts.factory.createIdentifier('v'); + } else if(isEnumType(mapType.typeArguments![1])) { + writeValue = ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword) ); - } else { - itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; + } + else { + const itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); + writeValue = ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), undefined, [ - ts.factory.createIdentifier('v'), - ts.factory.createIdentifier('w') + ts.factory.createIdentifier('v') ] ); } - propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'startObject'), - undefined, - [] - ))); - - propertyStatements.push( - ts.factory.createExpressionStatement( - ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName) - , 'forEach'), undefined, [ - ts.factory.createArrowFunction( - undefined, + propertyStatements.push(ts.factory.createBlock([ + ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration('m', undefined, - [ - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), - ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') - ], undefined, - ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), - ts.factory.createBlock([ - ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + ts.factory.createNewExpression(ts.factory.createIdentifier('Map'), + [ + ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) + ], + [])) + ], ts.NodeFlags.Const) + ), + ts.factory.createExpressionStatement(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), + undefined, + [ + ts.factory.createStringLiteral(jsonName), + ts.factory.createIdentifier('m') + ] + )), + + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + 'forEach' + ), + undefined, + [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('m'), 'set'), undefined, - [ts.factory.createIdentifier('k')] - )), - ts.factory.createExpressionStatement(writeValue) - ]) - ) - ]) + [ + // todo: key to string + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier('k'), + 'toString' + ), + undefined, + [] + ), + writeValue + ] + ) + ) + ] + ) ) - ); - - propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endObject'), - undefined, - [] - ))); - + ])); } else if (isImmutable(type.type)) { + let itemSerializer = type.type.symbol.name; + importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), undefined, [ - ts.factory.createStringLiteral(jsonName) - ] - ))); - - let itemSerializer = type.type.symbol.name; - importer(itemSerializer, findModule(type.type, program.getCompilerOptions())); - propertyStatements.push( - ts.factory.createExpressionStatement( + ts.factory.createStringLiteral(jsonName), ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('w') ] - ) - ) - ); + ), + ] + ))); } else { + let itemSerializer = type.type.symbol.name + "Serializer"; + importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); propertyStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'prop'), + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('o'), 'set'), undefined, [ - ts.factory.createStringLiteral(jsonName) + ts.factory.createStringLiteral(jsonName), + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), + [], + [ + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), + ] + ), ] ))); - - let itemSerializer = type.type.symbol.name + "Serializer"; - importer(itemSerializer, findSerializerModule(type.type, program.getCompilerOptions())); - - const writeValue: ts.Statement = ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'toJson'), - [], - [ - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('w'), - ] - )); - - if (type.isNullable) { - propertyStatements.push(ts.factory.createIfStatement( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createBlock([ - writeValue - ]), - ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'null'), - undefined, - [] - )) - )); - } else { - propertyStatements.push(writeValue); - } } if (prop.target) { @@ -472,10 +468,7 @@ function generateToJsonBody( statements.push(...propertyStatements); } - statements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('w'), 'endObject'), - undefined, [] - ))); + statements.push(ts.factory.createReturnStatement(ts.factory.createIdentifier('o'))); return ts.factory.createBlock(addNewLines(statements)) } @@ -485,7 +478,6 @@ function createToJsonMethod(program: ts.Program, propertiesToSerialize: JsonProperty[], importer: (name: string, module: string) => void ) { - importer('JsonWriter', '@src/io/JsonWriter'); return ts.factory.createMethodDeclaration( undefined, [ @@ -510,17 +502,12 @@ function createToJsonMethod(program: ts.Program, ), ts.factory.createLiteralTypeNode(ts.factory.createNull()) ]) - ), - ts.factory.createParameterDeclaration( - undefined, - undefined, - undefined, - 'w', - undefined, - ts.factory.createTypeReferenceNode('JsonWriter') ) ], - ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword), + ts.factory.createUnionTypeNode([ + createStringUnknownMapNode(), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]), generateToJsonBody(program, propertiesToSerialize, importer) ) } @@ -528,36 +515,36 @@ function createToJsonMethod(program: ts.Program, // // setProperty -function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecker) { +function isPrimitiveFromJson(type: ts.Type, typeChecker: ts.TypeChecker) { if (!type) { - return null; + return false; } const isArray = isTypedArray(type); const arrayItemType = unwrapArrayItemType(type, typeChecker); if (hasFlag(type, ts.TypeFlags.Unknown)) { - return "unknown"; + return true; } if (hasFlag(type, ts.TypeFlags.Number)) { - return "number"; + return true; } if (hasFlag(type, ts.TypeFlags.String)) { - return "string"; + return true; } if (hasFlag(type, ts.TypeFlags.Boolean)) { - return "boolean"; + return true; } if (arrayItemType) { if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Number)) { - return "numberArray"; + return true; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.String)) { - return "stringArray"; + return true; } if (isArray && hasFlag(arrayItemType, ts.TypeFlags.Boolean)) { - return "booleanArray"; + return true; } } else if (type.symbol) { switch (type.symbol.name) { @@ -569,7 +556,7 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke case 'Int32Array': case 'Float32Array': case 'Float64Array': - return type.symbol.name.substr(0, 1).toLowerCase() + type.symbol.name.substr(1); + return true; } } @@ -580,16 +567,44 @@ function getReadMethodNameForPrimitive(type: ts.Type, typeChecker: ts.TypeChecke function createEnumMapping(type: ts.Type): ts.Expression { return ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('r'), - 'enum' + ts.factory.createIdentifier('JsonHelper'), + 'parseEnum' ), [ts.factory.createTypeReferenceNode(type.symbol.name)], [ + ts.factory.createIdentifier('v'), ts.factory.createIdentifier(type.symbol.name) ] ); } +function stripRanges(node: T) { + (node as any).pos = -1; + (node as any).end = -1; + return node; +} + +function getDeepMutableClone(node: T): T { + return ts.transform(node, [ + context => node => deepCloneWithContext(node, context) + ]).transformed[0]; + + function deepCloneWithContext( + node: T, + context: ts.TransformationContext + ): T { + const clonedNode = ts.visitEachChild( + stripRanges(ts.getMutableClone(node)), + child => deepCloneWithContext(child, context), + context + ); + (clonedNode as any).parent = undefined as any; + ts.forEachChild(clonedNode, child => { (child as any).parent = clonedNode; }); + return clonedNode; + } +} + + function generateSetPropertyBody(program: ts.Program, propertiesToSerialize: JsonProperty[], importer: (name: string, module: string) => void @@ -613,26 +628,17 @@ function generateSetPropertyBody(program: ts.Program, ); }; - const primitiveRead = getReadMethodNameForPrimitive(type.type!, typeChecker); - if (primitiveRead) { - const read = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('r'), - primitiveRead - ), - undefined, - [] - ); - if (type.isNullable) { - caseStatements.push(assignField(read)); - } else { - caseStatements.push(assignField(ts.factory.createNonNullExpression(read))); - } + if (isPrimitiveFromJson(type.type!, typeChecker)) { + caseStatements.push(assignField(ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + getDeepMutableClone(prop.property.type!) + ))); caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isEnumType(type.type)) { // obj.fieldName = enummapping // return true; importer(type.type.symbol!.name, findModule(type.type, program.getCompilerOptions())); + importer('JsonHelper', '@src/io/JsonHelper'); const read = createEnumMapping(type.type); if (type.isNullable) { caseStatements.push(assignField(read)); @@ -661,18 +667,17 @@ function generateSetPropertyBody(program: ts.Program, const loopItems = [ assignField(ts.factory.createArrayLiteralExpression(undefined)), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startArray'), - undefined, - [] - ) - ), - ts.factory.createWhileStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextItem'), - undefined, - [] + ts.factory.createForOfStatement( + undefined, + ts.factory.createVariableDeclarationList([ts.factory.createVariableDeclaration('o')], ts.NodeFlags.Const), + ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + ts.factory.createArrayTypeNode( + ts.factory.createUnionTypeNode([ + createStringUnknownMapNode(), + ts.factory.createLiteralTypeNode(ts.factory.createNull()) + ]) + ) ), ts.factory.createBlock([ ts.factory.createVariableStatement( @@ -693,7 +698,7 @@ function generateSetPropertyBody(program: ts.Program, undefined, [ ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('r') + ts.factory.createIdentifier('o') ] ), ts.factory.createExpressionStatement( @@ -722,18 +727,11 @@ function generateSetPropertyBody(program: ts.Program, ) ].filter(s => !!s) as ts.Statement[]) ), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endArray'), - undefined, - [] - ) - ), ]; if (type.isNullable) { caseStatements.push(ts.factory.createIfStatement( - ts.factory.createIdentifier('value'), + ts.factory.createIdentifier('v'), ts.factory.createBlock(loopItems) )); } else { @@ -750,37 +748,39 @@ function generateSetPropertyBody(program: ts.Program, let mapKey; if (isEnumType(mapType.typeArguments![0])) { importer(mapType.typeArguments![0].symbol!.name, findModule(mapType.typeArguments![0], program.getCompilerOptions())); - mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'enumProp'), + importer('JsonHelper', '@src/io/JsonHelper'); + mapKey = ts.factory.createNonNullExpression(ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonHelper'), 'parseEnum'), [ts.factory.createTypeReferenceNode(mapType.typeArguments![0].symbol!.name)], - [ts.factory.createIdentifier(mapType.typeArguments![0].symbol!.name)] - ); + [ + ts.factory.createIdentifier('k'), + ts.factory.createIdentifier(mapType.typeArguments![0].symbol!.name), + ] + )); } else if (isNumberType(mapType.typeArguments![0])) { mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'numberProp'), + ts.factory.createIdentifier('parseInt'), undefined, - [] + [ + ts.factory.createIdentifier('k') + ] ); } else { - mapKey = ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'prop'), - undefined, - [] - ); + mapKey = ts.factory.createIdentifier('k'); } let mapValue; let itemSerializer: string = ''; - const primitiveReadForValue = getReadMethodNameForPrimitive(mapType.typeArguments![1], typeChecker); - if (primitiveReadForValue) { - mapValue = ts.factory.createNonNullExpression(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier('r'), - primitiveReadForValue - ), - undefined, - [] - )); + if (isPrimitiveFromJson(mapType.typeArguments![1], typeChecker)) { + // const isNullable = mapType.typeArguments![1].flags & ts.TypeFlags.Union + // && !!(mapType.typeArguments![1] as ts.UnionType).types.find(t => t.flags & ts.TypeFlags.Null); + + mapValue = ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + ts.isTypeReferenceNode(prop.property.type!) && prop.property.type.typeArguments + ? getDeepMutableClone(prop.property.type.typeArguments[1]) + : ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) + ); } else { itemSerializer = mapType.typeArguments![1].symbol.name + "Serializer"; importer(itemSerializer, findSerializerModule(mapType.typeArguments![1], program.getCompilerOptions())); @@ -797,62 +797,74 @@ function generateSetPropertyBody(program: ts.Program, typeChecker.typeToTypeNode(mapType.typeArguments![1], undefined, undefined)!, ], []))); - caseStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'startObject'), - undefined, [] - ))); - - caseStatements.push(ts.factory.createWhileStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'nextProp'), - undefined, - [] - ), - ts.factory.createBlock([ - !primitiveReadForValue && ts.factory.createVariableStatement( + caseStatements.push( + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + createStringUnknownMapNode() + ), + 'forEach' + ), undefined, - ts.factory.createVariableDeclarationList([ - ts.factory.createVariableDeclaration('i', - undefined, undefined, - ts.factory.createNewExpression(ts.factory.createIdentifier(mapType.typeArguments![1].symbol.name), undefined, []) + [ + ts.factory.createArrowFunction( + undefined, + undefined, + [ + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'v'), + ts.factory.createParameterDeclaration(undefined, undefined, undefined, 'k') + ], + undefined, + ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), + ts.factory.createBlock(addNewLines([ + itemSerializer.length > 0 && ts.factory.createVariableStatement( + undefined, + ts.factory.createVariableDeclarationList([ + ts.factory.createVariableDeclaration('i', + undefined, undefined, + ts.factory.createNewExpression(ts.factory.createIdentifier(mapType.typeArguments![1].symbol.name), undefined, []) + ) + ], ts.NodeFlags.Const), + ), + itemSerializer.length > 0 && ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + ts.factory.createPropertyAccessExpression( + ts.factory.createIdentifier(itemSerializer), + 'fromJson' + ), + undefined, + [ + ts.factory.createIdentifier('i'), + ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + createStringUnknownMapNode() + ), + ] + ) + ), + ts.factory.createExpressionStatement( + ts.factory.createCallExpression( + collectionAddMethod + ? ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), collectionAddMethod) + : ts.factory.createPropertyAccessExpression( + ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)), + ts.factory.createIdentifier('set') + ), + undefined, + [ + mapKey, + mapValue + ] + ) + ) + ].filter(s => !!s) as ts.Statement[])) ) - ], ts.NodeFlags.Const), - ), - !primitiveReadForValue && ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression( - ts.factory.createIdentifier(itemSerializer), - 'fromJson' - ), - undefined, - [ - ts.factory.createIdentifier('i'), - ts.factory.createIdentifier('r'), - ] - ) - ), - ts.factory.createExpressionStatement( - ts.factory.createCallExpression( - collectionAddMethod - ? ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), collectionAddMethod) - : ts.factory.createPropertyAccessExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), ts.factory.createIdentifier(fieldName)), - ts.factory.createIdentifier('set') - ), - undefined, - [ - mapKey, - mapValue - ] - ) + ] ) - ].filter(s => !!s) as ts.Statement[]) - )); - - caseStatements.push(ts.factory.createExpressionStatement(ts.factory.createCallExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'endObject'), - undefined, [] - ))); + ) + ); caseStatements.push(ts.factory.createReturnStatement(ts.factory.createTrue())); } else if (isImmutable(type.type)) { @@ -870,7 +882,7 @@ function generateSetPropertyBody(program: ts.Program, ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(itemSerializer), 'fromJson'), [], [ - ts.factory.createIdentifier('r') + ts.factory.createIdentifier('v') ] ), ts.factory @@ -913,7 +925,10 @@ function generateSetPropertyBody(program: ts.Program, [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('r') + ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + createStringUnknownMapNode() + ) ] ) ), @@ -921,11 +936,7 @@ function generateSetPropertyBody(program: ts.Program, ] : [ ts.factory.createIfStatement( - ts.factory.createBinaryExpression( - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('r'), 'currentValueType'), - ts.SyntaxKind.ExclamationEqualsEqualsToken, - ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JsonValueType'), 'Null'), - ), + ts.factory.createIdentifier('v'), ts.factory.createBlock([ assignField(ts.factory.createNewExpression( ts.factory.createIdentifier(type.type.symbol.name), @@ -939,7 +950,10 @@ function generateSetPropertyBody(program: ts.Program, [], [ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('obj'), fieldName), - ts.factory.createIdentifier('r') + ts.factory.createAsExpression( + ts.factory.createIdentifier('v'), + createStringUnknownMapNode() + ) ] ) ) @@ -1000,7 +1014,7 @@ function generateSetPropertyBody(program: ts.Program, [], [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('c'), 'length')] ), - ts.factory.createIdentifier('r') + ts.factory.createIdentifier('v') ] ), ts.factory.createBlock([ @@ -1031,7 +1045,7 @@ function generateSetPropertyBody(program: ts.Program, } } - if(cases.length > 0){ + if (cases.length > 0) { const switchExpr = ts.factory.createSwitchStatement(ts.factory.createIdentifier('property'), ts.factory.createCaseBlock(cases)); statements.unshift(switchExpr); } @@ -1081,9 +1095,9 @@ function createSetPropertyMethod( undefined, undefined, undefined, - 'r', + 'v', undefined, - ts.factory.createTypeReferenceNode('JsonReader') + ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword) ) ], ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword), diff --git a/src.csharp/AlphaTab/AlphaTab.csproj b/src.csharp/AlphaTab/AlphaTab.csproj index 879026aea..89e3e356f 100644 --- a/src.csharp/AlphaTab/AlphaTab.csproj +++ b/src.csharp/AlphaTab/AlphaTab.csproj @@ -17,7 +17,6 @@ Generated\%(RecursiveDir)\%(Filename)%(Extension) - diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs index 2fb1f32d1..d6eb420ec 100644 --- a/src.csharp/AlphaTab/Core/EcmaScript/Array.cs +++ b/src.csharp/AlphaTab/Core/EcmaScript/Array.cs @@ -11,11 +11,6 @@ public static bool IsArray(object? o) return o is IList; } - public static IList From(IList x) - { - return x; - } - public static IList From(IEnumerable x) { return x.ToList(); diff --git a/src.csharp/AlphaTab/Core/EcmaScript/Object.cs b/src.csharp/AlphaTab/Core/EcmaScript/Object.cs deleted file mode 100644 index 33ddd23f1..000000000 --- a/src.csharp/AlphaTab/Core/EcmaScript/Object.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; - -namespace AlphaTab.Core.EcmaScript -{ - internal static class Object - { - public static IList Keys(object p) - { - if (p is IDictionary d) - { - return d.Keys.OfType().Select(o => o.ToString()).ToList(); - } - - return p.GetType() - .GetProperties(BindingFlags.Instance | BindingFlags.Public) - .Select(prop => prop.Name) - .ToList(); - } - } -} diff --git a/src.csharp/AlphaTab/IO/JsonReader.cs b/src.csharp/AlphaTab/IO/JsonReader.cs deleted file mode 100644 index 1970382ed..000000000 --- a/src.csharp/AlphaTab/IO/JsonReader.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace AlphaTab.Io -{ - partial class JsonReader - { - private T ParseEnum(string value, object? enumType) - { - return (T) System.Enum.Parse(typeof(T), value, true); - } - - private T NumberToEnum(double value) - { - return (T)(object)(int) value; - } - } -} diff --git a/src.csharp/AlphaTab/IO/JsonWriter.cs b/src.csharp/AlphaTab/IO/JsonWriter.cs deleted file mode 100644 index 608df08f2..000000000 --- a/src.csharp/AlphaTab/IO/JsonWriter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Globalization; - -namespace AlphaTab.Io -{ - partial class JsonWriter - { - private double EnumToNumber(T enumValue) - { - if (enumValue is IConvertible c) - { - return c.ToDouble(CultureInfo.InvariantCulture); - } - return double.NaN; - } - } -} diff --git a/src.csharp/AlphaTab/IO/ObjectToMap.cs b/src.csharp/AlphaTab/IO/ObjectToMap.cs deleted file mode 100644 index 6b737ffa2..000000000 --- a/src.csharp/AlphaTab/IO/ObjectToMap.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace AlphaTab.Io -{ - partial class ReaderStackItem - { - private static IDictionary? ObjectToMap(object? obj) - { - switch (obj) - { - case null: - return null; - case IDictionary d: - return d; - default: - throw new ArgumentException("Can only handle IDictionary in JsonReader"); - } - } - } -} diff --git a/src.csharp/AlphaTab/Io/JsonHelper.cs b/src.csharp/AlphaTab/Io/JsonHelper.cs new file mode 100644 index 000000000..9e8738fcb --- /dev/null +++ b/src.csharp/AlphaTab/Io/JsonHelper.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace AlphaTab.Io +{ + internal static partial class JsonHelper + { + // ReSharper disable once UnusedParameter.Global + public static T? ParseEnum(object? o, Type _) where T : struct + { + switch (o) + { + case string s: + return Enum.TryParse(s, true, out T value) ? value : new T?(); + case double d: + return (T) (object) (int) d; + case int _: + return (T) o; + case null: + return null; + case T t: + return t; + } + + throw new AlphaTabError(AlphaTabErrorType.Format, $"Could not parse enum value '{o}' [({o.GetType()}]"); + } + + public static void ForEach(object o, Action func) + { + switch (o) + { + case IDictionary d: + foreach (var kvp in d) + { + func(kvp.Value, kvp.Key); + } + + break; + case IDictionary d: + foreach (DictionaryEntry entry in d) + { + func(entry.Value, Convert.ToString(entry.Key)); + } + + break; + } + + // ignore + } + } +} diff --git a/src/Settings.ts b/src/Settings.ts index 88faab58d..9ff8e01fa 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -3,23 +3,12 @@ import { DisplaySettings } from '@src/DisplaySettings'; import { ImporterSettings } from '@src/ImporterSettings'; import { FingeringMode, NotationMode, NotationSettings, NotationElement } from '@src/NotationSettings'; import { PlayerSettings } from '@src/PlayerSettings'; -import { SettingsSerializer } from './generated/SettingsSerializer'; -import { JsonReader } from './io/JsonReader'; /** * This public class contains instance specific settings for alphaTab * @json */ export class Settings { - /** - * @target web - */ - public fillFromDataAttributes(dataAttributes: Map): void { - dataAttributes.forEach((v, k) => { - SettingsSerializer.setProperty(this, k.toLowerCase(), new JsonReader(v)); - }); - } - /** * The core settings control the general behavior of alphatab like * what modules are active. diff --git a/src/generated/CoreSettingsSerializer.ts b/src/generated/CoreSettingsSerializer.ts index 5ce3437b7..cfa36d789 100644 --- a/src/generated/CoreSettingsSerializer.ts +++ b/src/generated/CoreSettingsSerializer.ts @@ -4,86 +4,79 @@ // the code is regenerated. // import { CoreSettings } from "@src/CoreSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { LogLevel } from "@src/LogLevel"; export class CoreSettingsSerializer { - public static fromJson(obj: CoreSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: CoreSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: CoreSettings | null, w: JsonWriter): void { + public static toJson(obj: CoreSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); + const o = new Map(); /*@target web*/ - w.string(obj.scriptFile, "scriptFile"); + o.set("scriptFile", obj.scriptFile); /*@target web*/ - w.string(obj.fontDirectory, "fontDirectory"); + o.set("fontDirectory", obj.fontDirectory); /*@target web*/ - w.string(obj.file, "file"); + o.set("file", obj.file); /*@target web*/ - w.boolean(obj.tex, "tex"); + o.set("tex", obj.tex); /*@target web*/ - w.unknown(obj.tracks, "tracks"); + o.set("tracks", obj.tracks); /*@target web*/ - w.number(obj.visibilityCheckInterval, "visibilityCheckInterval"); - w.boolean(obj.enableLazyLoading, "enableLazyLoading"); - w.string(obj.engine, "engine"); - w.enum(obj.logLevel, "logLevel"); - w.boolean(obj.useWorkers, "useWorkers"); - w.boolean(obj.includeNoteBounds, "includeNoteBounds"); - w.endObject(); + o.set("visibilityCheckInterval", obj.visibilityCheckInterval); + o.set("enableLazyLoading", obj.enableLazyLoading); + o.set("engine", obj.engine); + o.set("logLevel", (obj.logLevel as number)); + o.set("useWorkers", obj.useWorkers); + o.set("includeNoteBounds", obj.includeNoteBounds); + return o; } - public static setProperty(obj: CoreSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: CoreSettings, property: string, v: unknown): boolean { switch (property) { /*@target web*/ case "scriptfile": - obj.scriptFile = r.string(); + obj.scriptFile = (v as string | null); return true; /*@target web*/ case "fontdirectory": - obj.fontDirectory = r.string(); + obj.fontDirectory = (v as string | null); return true; /*@target web*/ case "file": - obj.file = r.string(); + obj.file = (v as string | null); return true; /*@target web*/ case "tex": - obj.tex = (r.boolean()!); + obj.tex = (v as boolean); return true; /*@target web*/ case "tracks": - obj.tracks = (r.unknown()!); + obj.tracks = (v as unknown); return true; /*@target web*/ case "visibilitycheckinterval": - obj.visibilityCheckInterval = (r.number()!); + obj.visibilityCheckInterval = (v as number); return true; case "enablelazyloading": - obj.enableLazyLoading = (r.boolean()!); + obj.enableLazyLoading = (v as boolean); return true; case "engine": - obj.engine = (r.string()!); + obj.engine = (v as string); return true; case "loglevel": - obj.logLevel = (r.enum(LogLevel)!); + obj.logLevel = (JsonHelper.parseEnum(v, LogLevel)!); return true; case "useworkers": - obj.useWorkers = (r.boolean()!); + obj.useWorkers = (v as boolean); return true; case "includenotebounds": - obj.includeNoteBounds = (r.boolean()!); + obj.includeNoteBounds = (v as boolean); return true; } return false; diff --git a/src/generated/DisplaySettingsSerializer.ts b/src/generated/DisplaySettingsSerializer.ts index 145b4cbd5..a44eaf92d 100644 --- a/src/generated/DisplaySettingsSerializer.ts +++ b/src/generated/DisplaySettingsSerializer.ts @@ -4,80 +4,72 @@ // the code is regenerated. // import { DisplaySettings } from "@src/DisplaySettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { RenderingResourcesSerializer } from "@src/generated/RenderingResourcesSerializer"; import { LayoutMode } from "@src/DisplaySettings"; import { StaveProfile } from "@src/DisplaySettings"; export class DisplaySettingsSerializer { - public static fromJson(obj: DisplaySettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: DisplaySettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: DisplaySettings | null, w: JsonWriter): void { + public static toJson(obj: DisplaySettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.scale, "scale"); - w.number(obj.stretchForce, "stretchForce"); - w.enum(obj.layoutMode, "layoutMode"); - w.enum(obj.staveProfile, "staveProfile"); - w.number(obj.barsPerRow, "barsPerRow"); - w.number(obj.startBar, "startBar"); - w.number(obj.barCount, "barCount"); - w.number(obj.barCountPerPartial, "barCountPerPartial"); - w.prop("resources"); - RenderingResourcesSerializer.toJson(obj.resources, w); - w.numberArray(obj.padding, "padding"); - w.endObject(); + const o = new Map(); + o.set("scale", obj.scale); + o.set("stretchForce", obj.stretchForce); + o.set("layoutMode", (obj.layoutMode as number)); + o.set("staveProfile", (obj.staveProfile as number)); + o.set("barsPerRow", obj.barsPerRow); + o.set("startBar", obj.startBar); + o.set("barCount", obj.barCount); + o.set("barCountPerPartial", obj.barCountPerPartial); + o.set("resources", RenderingResourcesSerializer.toJson(obj.resources)); + o.set("padding", obj.padding); + return o; } - public static setProperty(obj: DisplaySettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: DisplaySettings, property: string, v: unknown): boolean { switch (property) { case "scale": - obj.scale = (r.number()!); + obj.scale = (v as number); return true; case "stretchforce": - obj.stretchForce = (r.number()!); + obj.stretchForce = (v as number); return true; case "layoutmode": - obj.layoutMode = (r.enum(LayoutMode)!); + obj.layoutMode = (JsonHelper.parseEnum(v, LayoutMode)!); return true; case "staveprofile": - obj.staveProfile = (r.enum(StaveProfile)!); + obj.staveProfile = (JsonHelper.parseEnum(v, StaveProfile)!); return true; case "barsperrow": - obj.barsPerRow = (r.number()!); + obj.barsPerRow = (v as number); return true; case "startbar": - obj.startBar = (r.number()!); + obj.startBar = (v as number); return true; case "barcount": - obj.barCount = (r.number()!); + obj.barCount = (v as number); return true; case "barcountperpartial": - obj.barCountPerPartial = (r.number()!); + obj.barCountPerPartial = (v as number); return true; case "padding": - obj.padding = r.numberArray(); + obj.padding = (v as number[] | null); return true; } if (["resources"].indexOf(property) >= 0) { - RenderingResourcesSerializer.fromJson(obj.resources, r); + RenderingResourcesSerializer.fromJson(obj.resources, (v as Map)); return true; } else { for (const c of ["resources"]) { if (property.indexOf(c) === 0) { - if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), r)) { + if (RenderingResourcesSerializer.setProperty(obj.resources, property.substring(c.length), v)) { return true; } } diff --git a/src/generated/ImporterSettingsSerializer.ts b/src/generated/ImporterSettingsSerializer.ts index cc325b4ea..694f9991f 100644 --- a/src/generated/ImporterSettingsSerializer.ts +++ b/src/generated/ImporterSettingsSerializer.ts @@ -4,37 +4,30 @@ // the code is regenerated. // import { ImporterSettings } from "@src/ImporterSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class ImporterSettingsSerializer { - public static fromJson(obj: ImporterSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: ImporterSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: ImporterSettings | null, w: JsonWriter): void { + public static toJson(obj: ImporterSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.string(obj.encoding, "encoding"); - w.boolean(obj.mergePartGroupsInMusicXml, "mergePartGroupsInMusicXml"); - w.endObject(); + const o = new Map(); + o.set("encoding", obj.encoding); + o.set("mergePartGroupsInMusicXml", obj.mergePartGroupsInMusicXml); + return o; } - public static setProperty(obj: ImporterSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: ImporterSettings, property: string, v: unknown): boolean { switch (property) { case "encoding": - obj.encoding = (r.string()!); + obj.encoding = (v as string); return true; case "mergepartgroupsinmusicxml": - obj.mergePartGroupsInMusicXml = (r.boolean()!); + obj.mergePartGroupsInMusicXml = (v as boolean); return true; } return false; diff --git a/src/generated/NotationSettingsSerializer.ts b/src/generated/NotationSettingsSerializer.ts index 26a39f615..deba6f6e7 100644 --- a/src/generated/NotationSettingsSerializer.ts +++ b/src/generated/NotationSettingsSerializer.ts @@ -4,85 +4,77 @@ // the code is regenerated. // import { NotationSettings } from "@src/NotationSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { NotationMode } from "@src/NotationSettings"; import { FingeringMode } from "@src/NotationSettings"; import { NotationElement } from "@src/NotationSettings"; import { TabRhythmMode } from "@src/NotationSettings"; export class NotationSettingsSerializer { - public static fromJson(obj: NotationSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: NotationSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: NotationSettings | null, w: JsonWriter): void { + public static toJson(obj: NotationSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; + } + const o = new Map(); + o.set("notationMode", (obj.notationMode as number)); + o.set("fingeringMode", (obj.fingeringMode as number)); + { + const m = new Map(); + o.set("elements", m); + obj.elements.forEach((v, k) => m.set(k.toString(), v)); } - w.startObject(); - w.enum(obj.notationMode, "notationMode"); - w.enum(obj.fingeringMode, "fingeringMode"); - w.prop("elements"); - w.startObject(); - obj.elements.forEach((v, k) => { w.prop(k); w.boolean(v); }); - w.endObject(); - w.enum(obj.rhythmMode, "rhythmMode"); - w.number(obj.rhythmHeight, "rhythmHeight"); - w.numberArray(obj.transpositionPitches, "transpositionPitches"); - w.numberArray(obj.displayTranspositionPitches, "displayTranspositionPitches"); - w.boolean(obj.smallGraceTabNotes, "smallGraceTabNotes"); - w.boolean(obj.extendBendArrowsOnTiedNotes, "extendBendArrowsOnTiedNotes"); - w.boolean(obj.extendLineEffectsToBeatEnd, "extendLineEffectsToBeatEnd"); - w.number(obj.slurHeight, "slurHeight"); - w.endObject(); + o.set("rhythmMode", (obj.rhythmMode as number)); + o.set("rhythmHeight", obj.rhythmHeight); + o.set("transpositionPitches", obj.transpositionPitches); + o.set("displayTranspositionPitches", obj.displayTranspositionPitches); + o.set("smallGraceTabNotes", obj.smallGraceTabNotes); + o.set("extendBendArrowsOnTiedNotes", obj.extendBendArrowsOnTiedNotes); + o.set("extendLineEffectsToBeatEnd", obj.extendLineEffectsToBeatEnd); + o.set("slurHeight", obj.slurHeight); + return o; } - public static setProperty(obj: NotationSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: NotationSettings, property: string, v: unknown): boolean { switch (property) { case "notationmode": - obj.notationMode = (r.enum(NotationMode)!); + obj.notationMode = (JsonHelper.parseEnum(v, NotationMode)!); return true; case "fingeringmode": - obj.fingeringMode = (r.enum(FingeringMode)!); + obj.fingeringMode = (JsonHelper.parseEnum(v, FingeringMode)!); return true; case "elements": obj.elements = new Map(); - r.startObject(); - while (r.nextProp()) { - obj.elements.set(r.enumProp(NotationElement), (r.boolean()!)); - } - r.endObject(); + (v as Map).forEach((v, k) => { + obj.elements.set((JsonHelper.parseEnum(k, NotationElement)!), (v as boolean)); + }); return true; case "rhythmmode": - obj.rhythmMode = (r.enum(TabRhythmMode)!); + obj.rhythmMode = (JsonHelper.parseEnum(v, TabRhythmMode)!); return true; case "rhythmheight": - obj.rhythmHeight = (r.number()!); + obj.rhythmHeight = (v as number); return true; case "transpositionpitches": - obj.transpositionPitches = (r.numberArray()!); + obj.transpositionPitches = (v as number[]); return true; case "displaytranspositionpitches": - obj.displayTranspositionPitches = (r.numberArray()!); + obj.displayTranspositionPitches = (v as number[]); return true; case "smallgracetabnotes": - obj.smallGraceTabNotes = (r.boolean()!); + obj.smallGraceTabNotes = (v as boolean); return true; case "extendbendarrowsontiednotes": - obj.extendBendArrowsOnTiedNotes = (r.boolean()!); + obj.extendBendArrowsOnTiedNotes = (v as boolean); return true; case "extendlineeffectstobeatend": - obj.extendLineEffectsToBeatEnd = (r.boolean()!); + obj.extendLineEffectsToBeatEnd = (v as boolean); return true; case "slurheight": - obj.slurHeight = (r.number()!); + obj.slurHeight = (v as number); return true; } return false; diff --git a/src/generated/PlayerSettingsSerializer.ts b/src/generated/PlayerSettingsSerializer.ts index 9dd9a850a..d761cc5d3 100644 --- a/src/generated/PlayerSettingsSerializer.ts +++ b/src/generated/PlayerSettingsSerializer.ts @@ -4,107 +4,98 @@ // the code is regenerated. // import { PlayerSettings } from "@src/PlayerSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; -import { VibratoPlaybackSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; -import { SlidePlaybackSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; +import { JsonHelper } from "@src/io/JsonHelper"; +import { VibratoPlaybackSettingsSerializer } from "@src/generated/VibratoPlaybackSettingsSerializer"; +import { SlidePlaybackSettingsSerializer } from "@src/generated/SlidePlaybackSettingsSerializer"; import { ScrollMode } from "@src/PlayerSettings"; export class PlayerSettingsSerializer { - public static fromJson(obj: PlayerSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: PlayerSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: PlayerSettings | null, w: JsonWriter): void { + public static toJson(obj: PlayerSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.string(obj.soundFont, "soundFont"); - w.string(obj.scrollElement, "scrollElement"); - w.boolean(obj.enablePlayer, "enablePlayer"); - w.boolean(obj.enableCursor, "enableCursor"); - w.boolean(obj.enableUserInteraction, "enableUserInteraction"); - w.number(obj.scrollOffsetX, "scrollOffsetX"); - w.number(obj.scrollOffsetY, "scrollOffsetY"); - w.enum(obj.scrollMode, "scrollMode"); - w.number(obj.scrollSpeed, "scrollSpeed"); - w.number(obj.songBookBendDuration, "songBookBendDuration"); - w.number(obj.songBookDipDuration, "songBookDipDuration"); - w.prop("vibrato"); - VibratoPlaybackSettingsSerializer.toJson(obj.vibrato, w); - w.prop("slide"); - SlidePlaybackSettingsSerializer.toJson(obj.slide, w); - w.boolean(obj.playTripletFeel, "playTripletFeel"); - w.endObject(); + const o = new Map(); + o.set("soundFont", obj.soundFont); + o.set("scrollElement", obj.scrollElement); + o.set("enablePlayer", obj.enablePlayer); + o.set("enableCursor", obj.enableCursor); + o.set("enableUserInteraction", obj.enableUserInteraction); + o.set("scrollOffsetX", obj.scrollOffsetX); + o.set("scrollOffsetY", obj.scrollOffsetY); + o.set("scrollMode", (obj.scrollMode as number)); + o.set("scrollSpeed", obj.scrollSpeed); + o.set("songBookBendDuration", obj.songBookBendDuration); + o.set("songBookDipDuration", obj.songBookDipDuration); + o.set("vibrato", VibratoPlaybackSettingsSerializer.toJson(obj.vibrato)); + o.set("slide", SlidePlaybackSettingsSerializer.toJson(obj.slide)); + o.set("playTripletFeel", obj.playTripletFeel); + return o; } - public static setProperty(obj: PlayerSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: PlayerSettings, property: string, v: unknown): boolean { switch (property) { case "soundfont": - obj.soundFont = r.string(); + obj.soundFont = (v as string | null); return true; case "scrollelement": - obj.scrollElement = (r.string()!); + obj.scrollElement = (v as string); return true; case "enableplayer": - obj.enablePlayer = (r.boolean()!); + obj.enablePlayer = (v as boolean); return true; case "enablecursor": - obj.enableCursor = (r.boolean()!); + obj.enableCursor = (v as boolean); return true; case "enableuserinteraction": - obj.enableUserInteraction = (r.boolean()!); + obj.enableUserInteraction = (v as boolean); return true; case "scrolloffsetx": - obj.scrollOffsetX = (r.number()!); + obj.scrollOffsetX = (v as number); return true; case "scrolloffsety": - obj.scrollOffsetY = (r.number()!); + obj.scrollOffsetY = (v as number); return true; case "scrollmode": - obj.scrollMode = (r.enum(ScrollMode)!); + obj.scrollMode = (JsonHelper.parseEnum(v, ScrollMode)!); return true; case "scrollspeed": - obj.scrollSpeed = (r.number()!); + obj.scrollSpeed = (v as number); return true; case "songbookbendduration": - obj.songBookBendDuration = (r.number()!); + obj.songBookBendDuration = (v as number); return true; case "songbookdipduration": - obj.songBookDipDuration = (r.number()!); + obj.songBookDipDuration = (v as number); return true; case "playtripletfeel": - obj.playTripletFeel = (r.boolean()!); + obj.playTripletFeel = (v as boolean); return true; } if (["vibrato"].indexOf(property) >= 0) { - VibratoPlaybackSettingsSerializer.fromJson(obj.vibrato, r); + VibratoPlaybackSettingsSerializer.fromJson(obj.vibrato, (v as Map)); return true; } else { for (const c of ["vibrato"]) { if (property.indexOf(c) === 0) { - if (VibratoPlaybackSettingsSerializer.setProperty(obj.vibrato, property.substring(c.length), r)) { + if (VibratoPlaybackSettingsSerializer.setProperty(obj.vibrato, property.substring(c.length), v)) { return true; } } } } if (["slide"].indexOf(property) >= 0) { - SlidePlaybackSettingsSerializer.fromJson(obj.slide, r); + SlidePlaybackSettingsSerializer.fromJson(obj.slide, (v as Map)); return true; } else { for (const c of ["slide"]) { if (property.indexOf(c) === 0) { - if (SlidePlaybackSettingsSerializer.setProperty(obj.slide, property.substring(c.length), r)) { + if (SlidePlaybackSettingsSerializer.setProperty(obj.slide, property.substring(c.length), v)) { return true; } } diff --git a/src/generated/RenderingResourcesSerializer.ts b/src/generated/RenderingResourcesSerializer.ts index 2ed794250..5b5e7d52b 100644 --- a/src/generated/RenderingResourcesSerializer.ts +++ b/src/generated/RenderingResourcesSerializer.ts @@ -4,116 +4,92 @@ // the code is regenerated. // import { RenderingResources } from "@src/RenderingResources"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { Font } from "@src/model/Font"; import { Color } from "@src/model/Color"; export class RenderingResourcesSerializer { - public static fromJson(obj: RenderingResources, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: RenderingResources, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: RenderingResources | null, w: JsonWriter): void { + public static toJson(obj: RenderingResources | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.prop("copyrightFont"); - Font.toJson(obj.copyrightFont, w); - w.prop("titleFont"); - Font.toJson(obj.titleFont, w); - w.prop("subTitleFont"); - Font.toJson(obj.subTitleFont, w); - w.prop("wordsFont"); - Font.toJson(obj.wordsFont, w); - w.prop("effectFont"); - Font.toJson(obj.effectFont, w); - w.prop("fretboardNumberFont"); - Font.toJson(obj.fretboardNumberFont, w); - w.prop("tablatureFont"); - Font.toJson(obj.tablatureFont, w); - w.prop("graceFont"); - Font.toJson(obj.graceFont, w); - w.prop("staffLineColor"); - Color.toJson(obj.staffLineColor, w); - w.prop("barSeparatorColor"); - Color.toJson(obj.barSeparatorColor, w); - w.prop("barNumberFont"); - Font.toJson(obj.barNumberFont, w); - w.prop("barNumberColor"); - Color.toJson(obj.barNumberColor, w); - w.prop("fingeringFont"); - Font.toJson(obj.fingeringFont, w); - w.prop("markerFont"); - Font.toJson(obj.markerFont, w); - w.prop("mainGlyphColor"); - Color.toJson(obj.mainGlyphColor, w); - w.prop("secondaryGlyphColor"); - Color.toJson(obj.secondaryGlyphColor, w); - w.prop("scoreInfoColor"); - Color.toJson(obj.scoreInfoColor, w); - w.endObject(); + const o = new Map(); + o.set("copyrightFont", Font.toJson(obj.copyrightFont)); + o.set("titleFont", Font.toJson(obj.titleFont)); + o.set("subTitleFont", Font.toJson(obj.subTitleFont)); + o.set("wordsFont", Font.toJson(obj.wordsFont)); + o.set("effectFont", Font.toJson(obj.effectFont)); + o.set("fretboardNumberFont", Font.toJson(obj.fretboardNumberFont)); + o.set("tablatureFont", Font.toJson(obj.tablatureFont)); + o.set("graceFont", Font.toJson(obj.graceFont)); + o.set("staffLineColor", Color.toJson(obj.staffLineColor)); + o.set("barSeparatorColor", Color.toJson(obj.barSeparatorColor)); + o.set("barNumberFont", Font.toJson(obj.barNumberFont)); + o.set("barNumberColor", Color.toJson(obj.barNumberColor)); + o.set("fingeringFont", Font.toJson(obj.fingeringFont)); + o.set("markerFont", Font.toJson(obj.markerFont)); + o.set("mainGlyphColor", Color.toJson(obj.mainGlyphColor)); + o.set("secondaryGlyphColor", Color.toJson(obj.secondaryGlyphColor)); + o.set("scoreInfoColor", Color.toJson(obj.scoreInfoColor)); + return o; } - public static setProperty(obj: RenderingResources, property: string, r: JsonReader): boolean { + public static setProperty(obj: RenderingResources, property: string, v: unknown): boolean { switch (property) { case "copyrightfont": - obj.copyrightFont = (Font.fromJson(r)!); + obj.copyrightFont = (Font.fromJson(v)!); return true; case "titlefont": - obj.titleFont = (Font.fromJson(r)!); + obj.titleFont = (Font.fromJson(v)!); return true; case "subtitlefont": - obj.subTitleFont = (Font.fromJson(r)!); + obj.subTitleFont = (Font.fromJson(v)!); return true; case "wordsfont": - obj.wordsFont = (Font.fromJson(r)!); + obj.wordsFont = (Font.fromJson(v)!); return true; case "effectfont": - obj.effectFont = (Font.fromJson(r)!); + obj.effectFont = (Font.fromJson(v)!); return true; case "fretboardnumberfont": - obj.fretboardNumberFont = (Font.fromJson(r)!); + obj.fretboardNumberFont = (Font.fromJson(v)!); return true; case "tablaturefont": - obj.tablatureFont = (Font.fromJson(r)!); + obj.tablatureFont = (Font.fromJson(v)!); return true; case "gracefont": - obj.graceFont = (Font.fromJson(r)!); + obj.graceFont = (Font.fromJson(v)!); return true; case "stafflinecolor": - obj.staffLineColor = (Color.fromJson(r)!); + obj.staffLineColor = (Color.fromJson(v)!); return true; case "barseparatorcolor": - obj.barSeparatorColor = (Color.fromJson(r)!); + obj.barSeparatorColor = (Color.fromJson(v)!); return true; case "barnumberfont": - obj.barNumberFont = (Font.fromJson(r)!); + obj.barNumberFont = (Font.fromJson(v)!); return true; case "barnumbercolor": - obj.barNumberColor = (Color.fromJson(r)!); + obj.barNumberColor = (Color.fromJson(v)!); return true; case "fingeringfont": - obj.fingeringFont = (Font.fromJson(r)!); + obj.fingeringFont = (Font.fromJson(v)!); return true; case "markerfont": - obj.markerFont = (Font.fromJson(r)!); + obj.markerFont = (Font.fromJson(v)!); return true; case "mainglyphcolor": - obj.mainGlyphColor = (Color.fromJson(r)!); + obj.mainGlyphColor = (Color.fromJson(v)!); return true; case "secondaryglyphcolor": - obj.secondaryGlyphColor = (Color.fromJson(r)!); + obj.secondaryGlyphColor = (Color.fromJson(v)!); return true; case "scoreinfocolor": - obj.scoreInfoColor = (Color.fromJson(r)!); + obj.scoreInfoColor = (Color.fromJson(v)!); return true; } return false; diff --git a/src/generated/SettingsSerializer.ts b/src/generated/SettingsSerializer.ts index 918f30d4a..922f10bb4 100644 --- a/src/generated/SettingsSerializer.ts +++ b/src/generated/SettingsSerializer.ts @@ -4,104 +4,92 @@ // the code is regenerated. // import { Settings } from "@src/Settings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { CoreSettingsSerializer } from "@src/generated/CoreSettingsSerializer"; import { DisplaySettingsSerializer } from "@src/generated/DisplaySettingsSerializer"; import { NotationSettingsSerializer } from "@src/generated/NotationSettingsSerializer"; import { ImporterSettingsSerializer } from "@src/generated/ImporterSettingsSerializer"; import { PlayerSettingsSerializer } from "@src/generated/PlayerSettingsSerializer"; export class SettingsSerializer { - public static fromJson(obj: Settings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Settings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Settings | null, w: JsonWriter): void { + public static toJson(obj: Settings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.prop("core"); - CoreSettingsSerializer.toJson(obj.core, w); - w.prop("display"); - DisplaySettingsSerializer.toJson(obj.display, w); - w.prop("notation"); - NotationSettingsSerializer.toJson(obj.notation, w); - w.prop("importer"); - ImporterSettingsSerializer.toJson(obj.importer, w); - w.prop("player"); - PlayerSettingsSerializer.toJson(obj.player, w); - w.endObject(); + const o = new Map(); + o.set("core", CoreSettingsSerializer.toJson(obj.core)); + o.set("display", DisplaySettingsSerializer.toJson(obj.display)); + o.set("notation", NotationSettingsSerializer.toJson(obj.notation)); + o.set("importer", ImporterSettingsSerializer.toJson(obj.importer)); + o.set("player", PlayerSettingsSerializer.toJson(obj.player)); + return o; } - public static setProperty(obj: Settings, property: string, r: JsonReader): boolean { + public static setProperty(obj: Settings, property: string, v: unknown): boolean { if (["core", ""].indexOf(property) >= 0) { - CoreSettingsSerializer.fromJson(obj.core, r); + CoreSettingsSerializer.fromJson(obj.core, (v as Map)); return true; } else { for (const c of ["core", ""]) { if (property.indexOf(c) === 0) { - if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), r)) { + if (CoreSettingsSerializer.setProperty(obj.core, property.substring(c.length), v)) { return true; } } } } if (["display", ""].indexOf(property) >= 0) { - DisplaySettingsSerializer.fromJson(obj.display, r); + DisplaySettingsSerializer.fromJson(obj.display, (v as Map)); return true; } else { for (const c of ["display", ""]) { if (property.indexOf(c) === 0) { - if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), r)) { + if (DisplaySettingsSerializer.setProperty(obj.display, property.substring(c.length), v)) { return true; } } } } if (["notation"].indexOf(property) >= 0) { - NotationSettingsSerializer.fromJson(obj.notation, r); + NotationSettingsSerializer.fromJson(obj.notation, (v as Map)); return true; } else { for (const c of ["notation"]) { if (property.indexOf(c) === 0) { - if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), r)) { + if (NotationSettingsSerializer.setProperty(obj.notation, property.substring(c.length), v)) { return true; } } } } if (["importer"].indexOf(property) >= 0) { - ImporterSettingsSerializer.fromJson(obj.importer, r); + ImporterSettingsSerializer.fromJson(obj.importer, (v as Map)); return true; } else { for (const c of ["importer"]) { if (property.indexOf(c) === 0) { - if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), r)) { + if (ImporterSettingsSerializer.setProperty(obj.importer, property.substring(c.length), v)) { return true; } } } } if (["player"].indexOf(property) >= 0) { - PlayerSettingsSerializer.fromJson(obj.player, r); + PlayerSettingsSerializer.fromJson(obj.player, (v as Map)); return true; } else { for (const c of ["player"]) { if (property.indexOf(c) === 0) { - if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), r)) { + if (PlayerSettingsSerializer.setProperty(obj.player, property.substring(c.length), v)) { return true; } } diff --git a/src/generated/SlidePlaybackSettingsSerializer.ts b/src/generated/SlidePlaybackSettingsSerializer.ts index af7194923..6ddbfac0e 100644 --- a/src/generated/SlidePlaybackSettingsSerializer.ts +++ b/src/generated/SlidePlaybackSettingsSerializer.ts @@ -4,41 +4,34 @@ // the code is regenerated. // import { SlidePlaybackSettings } from "@src/PlayerSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class SlidePlaybackSettingsSerializer { - public static fromJson(obj: SlidePlaybackSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: SlidePlaybackSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: SlidePlaybackSettings | null, w: JsonWriter): void { + public static toJson(obj: SlidePlaybackSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.simpleSlidePitchOffset, "simpleSlidePitchOffset"); - w.number(obj.simpleSlideDurationRatio, "simpleSlideDurationRatio"); - w.number(obj.shiftSlideDurationRatio, "shiftSlideDurationRatio"); - w.endObject(); + const o = new Map(); + o.set("simpleSlidePitchOffset", obj.simpleSlidePitchOffset); + o.set("simpleSlideDurationRatio", obj.simpleSlideDurationRatio); + o.set("shiftSlideDurationRatio", obj.shiftSlideDurationRatio); + return o; } - public static setProperty(obj: SlidePlaybackSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: SlidePlaybackSettings, property: string, v: unknown): boolean { switch (property) { case "simpleslidepitchoffset": - obj.simpleSlidePitchOffset = (r.number()!); + obj.simpleSlidePitchOffset = (v as number); return true; case "simpleslidedurationratio": - obj.simpleSlideDurationRatio = (r.number()!); + obj.simpleSlideDurationRatio = (v as number); return true; case "shiftslidedurationratio": - obj.shiftSlideDurationRatio = (r.number()!); + obj.shiftSlideDurationRatio = (v as number); return true; } return false; diff --git a/src/generated/VibratoPlaybackSettingsSerializer.ts b/src/generated/VibratoPlaybackSettingsSerializer.ts index 752c5f59f..fc540d62d 100644 --- a/src/generated/VibratoPlaybackSettingsSerializer.ts +++ b/src/generated/VibratoPlaybackSettingsSerializer.ts @@ -4,61 +4,54 @@ // the code is regenerated. // import { VibratoPlaybackSettings } from "@src/PlayerSettings"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class VibratoPlaybackSettingsSerializer { - public static fromJson(obj: VibratoPlaybackSettings, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: VibratoPlaybackSettings, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: VibratoPlaybackSettings | null, w: JsonWriter): void { + public static toJson(obj: VibratoPlaybackSettings | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.noteWideLength, "noteWideLength"); - w.number(obj.noteWideAmplitude, "noteWideAmplitude"); - w.number(obj.noteSlightLength, "noteSlightLength"); - w.number(obj.noteSlightAmplitude, "noteSlightAmplitude"); - w.number(obj.beatWideLength, "beatWideLength"); - w.number(obj.beatWideAmplitude, "beatWideAmplitude"); - w.number(obj.beatSlightLength, "beatSlightLength"); - w.number(obj.beatSlightAmplitude, "beatSlightAmplitude"); - w.endObject(); + const o = new Map(); + o.set("noteWideLength", obj.noteWideLength); + o.set("noteWideAmplitude", obj.noteWideAmplitude); + o.set("noteSlightLength", obj.noteSlightLength); + o.set("noteSlightAmplitude", obj.noteSlightAmplitude); + o.set("beatWideLength", obj.beatWideLength); + o.set("beatWideAmplitude", obj.beatWideAmplitude); + o.set("beatSlightLength", obj.beatSlightLength); + o.set("beatSlightAmplitude", obj.beatSlightAmplitude); + return o; } - public static setProperty(obj: VibratoPlaybackSettings, property: string, r: JsonReader): boolean { + public static setProperty(obj: VibratoPlaybackSettings, property: string, v: unknown): boolean { switch (property) { case "notewidelength": - obj.noteWideLength = (r.number()!); + obj.noteWideLength = (v as number); return true; case "notewideamplitude": - obj.noteWideAmplitude = (r.number()!); + obj.noteWideAmplitude = (v as number); return true; case "noteslightlength": - obj.noteSlightLength = (r.number()!); + obj.noteSlightLength = (v as number); return true; case "noteslightamplitude": - obj.noteSlightAmplitude = (r.number()!); + obj.noteSlightAmplitude = (v as number); return true; case "beatwidelength": - obj.beatWideLength = (r.number()!); + obj.beatWideLength = (v as number); return true; case "beatwideamplitude": - obj.beatWideAmplitude = (r.number()!); + obj.beatWideAmplitude = (v as number); return true; case "beatslightlength": - obj.beatSlightLength = (r.number()!); + obj.beatSlightLength = (v as number); return true; case "beatslightamplitude": - obj.beatSlightAmplitude = (r.number()!); + obj.beatSlightAmplitude = (v as number); return true; } return false; diff --git a/src/generated/model/AutomationSerializer.ts b/src/generated/model/AutomationSerializer.ts index a558f21ec..ce0d82a92 100644 --- a/src/generated/model/AutomationSerializer.ts +++ b/src/generated/model/AutomationSerializer.ts @@ -4,50 +4,43 @@ // the code is regenerated. // import { Automation } from "@src/model/Automation"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { AutomationType } from "@src/model/Automation"; export class AutomationSerializer { - public static fromJson(obj: Automation, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Automation, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Automation | null, w: JsonWriter): void { + public static toJson(obj: Automation | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.boolean(obj.isLinear, "isLinear"); - w.enum(obj.type, "type"); - w.number(obj.value, "value"); - w.number(obj.ratioPosition, "ratioPosition"); - w.string(obj.text, "text"); - w.endObject(); + const o = new Map(); + o.set("isLinear", obj.isLinear); + o.set("type", (obj.type as number)); + o.set("value", obj.value); + o.set("ratioPosition", obj.ratioPosition); + o.set("text", obj.text); + return o; } - public static setProperty(obj: Automation, property: string, r: JsonReader): boolean { + public static setProperty(obj: Automation, property: string, v: unknown): boolean { switch (property) { case "islinear": - obj.isLinear = (r.boolean()!); + obj.isLinear = (v as boolean); return true; case "type": - obj.type = (r.enum(AutomationType)!); + obj.type = (JsonHelper.parseEnum(v, AutomationType)!); return true; case "value": - obj.value = (r.number()!); + obj.value = (v as number); return true; case "ratioposition": - obj.ratioPosition = (r.number()!); + obj.ratioPosition = (v as number); return true; case "text": - obj.text = (r.string()!); + obj.text = (v as string); return true; } return false; diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index 11a2a7a56..da241461c 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -4,70 +4,56 @@ // the code is regenerated. // import { Bar } from "@src/model/Bar"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { VoiceSerializer } from "@src/generated/model/VoiceSerializer"; import { Clef } from "@src/model/Clef"; import { Ottavia } from "@src/model/Ottavia"; import { Voice } from "@src/model/Voice"; import { SimileMark } from "@src/model/SimileMark"; export class BarSerializer { - public static fromJson(obj: Bar, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Bar, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Bar | null, w: JsonWriter): void { + public static toJson(obj: Bar | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.number(obj.id, "id"); - w.number(obj.index, "index"); - w.enum(obj.clef, "clef"); - w.enum(obj.clefOttava, "clefOttava"); - w.prop("voices"); - w.startArray(); - for (const i of obj.voices) { - VoiceSerializer.toJson(i, w); + return null; } - w.endArray(); - w.enum(obj.simileMark, "simileMark"); - w.endObject(); + const o = new Map(); + o.set("id", obj.id); + o.set("index", obj.index); + o.set("clef", (obj.clef as number)); + o.set("clefOttava", (obj.clefOttava as number)); + o.set("voices", obj.voices.map(i => VoiceSerializer.toJson(i))); + o.set("simileMark", (obj.simileMark as number)); + return o; } - public static setProperty(obj: Bar, property: string, r: JsonReader): boolean { + public static setProperty(obj: Bar, property: string, v: unknown): boolean { switch (property) { case "id": - obj.id = (r.number()!); + obj.id = (v as number); return true; case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "clef": - obj.clef = (r.enum(Clef)!); + obj.clef = (JsonHelper.parseEnum(v, Clef)!); return true; case "clefottava": - obj.clefOttava = (r.enum(Ottavia)!); + obj.clefOttava = (JsonHelper.parseEnum(v, Ottavia)!); return true; case "voices": obj.voices = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Voice(); - VoiceSerializer.fromJson(i, r) + VoiceSerializer.fromJson(i, o) obj.addVoice(i); } - r.endArray(); return true; case "similemark": - obj.simileMark = (r.enum(SimileMark)!); + obj.simileMark = (JsonHelper.parseEnum(v, SimileMark)!); return true; } return false; diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index 00e645303..4a3e94c5a 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -4,9 +4,7 @@ // the code is regenerated. // import { Beat } from "@src/model/Beat"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { NoteSerializer } from "@src/generated/model/NoteSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; @@ -26,217 +24,191 @@ import { DynamicValue } from "@src/model/DynamicValue"; import { BeamDirection } from "@src/rendering/utils/BeamDirection"; import { BeatBeamingMode } from "@src/model/Beat"; export class BeatSerializer { - public static fromJson(obj: Beat, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Beat, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Beat | null, w: JsonWriter): void { + public static toJson(obj: Beat | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.number(obj.id, "id"); - w.number(obj.index, "index"); - w.prop("notes"); - w.startArray(); - for (const i of obj.notes) { - NoteSerializer.toJson(i, w); - } - w.endArray(); - w.boolean(obj.isEmpty, "isEmpty"); - w.enum(obj.whammyStyle, "whammyStyle"); - w.enum(obj.ottava, "ottava"); - w.boolean(obj.isLegatoOrigin, "isLegatoOrigin"); - w.enum(obj.duration, "duration"); - w.prop("automations"); - w.startArray(); - for (const i of obj.automations) { - AutomationSerializer.toJson(i, w); - } - w.endArray(); - w.number(obj.dots, "dots"); - w.boolean(obj.fadeIn, "fadeIn"); - w.stringArray(obj.lyrics, "lyrics"); - w.boolean(obj.hasRasgueado, "hasRasgueado"); - w.boolean(obj.pop, "pop"); - w.boolean(obj.slap, "slap"); - w.boolean(obj.tap, "tap"); - w.string(obj.text, "text"); - w.enum(obj.brushType, "brushType"); - w.number(obj.brushDuration, "brushDuration"); - w.number(obj.tupletDenominator, "tupletDenominator"); - w.number(obj.tupletNumerator, "tupletNumerator"); - w.boolean(obj.isContinuedWhammy, "isContinuedWhammy"); - w.enum(obj.whammyBarType, "whammyBarType"); - w.prop("whammyBarPoints"); - w.startArray(); - for (const i of obj.whammyBarPoints) { - BendPointSerializer.toJson(i, w); + return null; } - w.endArray(); - w.enum(obj.vibrato, "vibrato"); - w.string(obj.chordId, "chordId"); - w.enum(obj.graceType, "graceType"); - w.enum(obj.pickStroke, "pickStroke"); - w.enum(obj.tremoloSpeed, "tremoloSpeed"); - w.enum(obj.crescendo, "crescendo"); - w.number(obj.displayStart, "displayStart"); - w.number(obj.playbackStart, "playbackStart"); - w.number(obj.displayDuration, "displayDuration"); - w.number(obj.playbackDuration, "playbackDuration"); - w.enum(obj.dynamics, "dynamics"); - w.boolean(obj.invertBeamDirection, "invertBeamDirection"); - w.enum(obj.preferredBeamDirection, "preferredBeamDirection"); - w.boolean(obj.isEffectSlurOrigin, "isEffectSlurOrigin"); - w.enum(obj.beamingMode, "beamingMode"); - w.endObject(); + const o = new Map(); + o.set("id", obj.id); + o.set("index", obj.index); + o.set("notes", obj.notes.map(i => NoteSerializer.toJson(i))); + o.set("isEmpty", obj.isEmpty); + o.set("whammyStyle", (obj.whammyStyle as number)); + o.set("ottava", (obj.ottava as number)); + o.set("isLegatoOrigin", obj.isLegatoOrigin); + o.set("duration", (obj.duration as number)); + o.set("automations", obj.automations.map(i => AutomationSerializer.toJson(i))); + o.set("dots", obj.dots); + o.set("fadeIn", obj.fadeIn); + o.set("lyrics", obj.lyrics); + o.set("hasRasgueado", obj.hasRasgueado); + o.set("pop", obj.pop); + o.set("slap", obj.slap); + o.set("tap", obj.tap); + o.set("text", obj.text); + o.set("brushType", (obj.brushType as number)); + o.set("brushDuration", obj.brushDuration); + o.set("tupletDenominator", obj.tupletDenominator); + o.set("tupletNumerator", obj.tupletNumerator); + o.set("isContinuedWhammy", obj.isContinuedWhammy); + o.set("whammyBarType", (obj.whammyBarType as number)); + o.set("whammyBarPoints", obj.whammyBarPoints.map(i => BendPointSerializer.toJson(i))); + o.set("vibrato", (obj.vibrato as number)); + o.set("chordId", obj.chordId); + o.set("graceType", (obj.graceType as number)); + o.set("pickStroke", (obj.pickStroke as number)); + o.set("tremoloSpeed", (obj.tremoloSpeed as number | null)); + o.set("crescendo", (obj.crescendo as number)); + o.set("displayStart", obj.displayStart); + o.set("playbackStart", obj.playbackStart); + o.set("displayDuration", obj.displayDuration); + o.set("playbackDuration", obj.playbackDuration); + o.set("dynamics", (obj.dynamics as number)); + o.set("invertBeamDirection", obj.invertBeamDirection); + o.set("preferredBeamDirection", (obj.preferredBeamDirection as number | null)); + o.set("isEffectSlurOrigin", obj.isEffectSlurOrigin); + o.set("beamingMode", (obj.beamingMode as number)); + return o; } - public static setProperty(obj: Beat, property: string, r: JsonReader): boolean { + public static setProperty(obj: Beat, property: string, v: unknown): boolean { switch (property) { case "id": - obj.id = (r.number()!); + obj.id = (v as number); return true; case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "notes": obj.notes = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Note(); - NoteSerializer.fromJson(i, r) + NoteSerializer.fromJson(i, o) obj.addNote(i); } - r.endArray(); return true; case "isempty": - obj.isEmpty = (r.boolean()!); + obj.isEmpty = (v as boolean); return true; case "whammystyle": - obj.whammyStyle = (r.enum(BendStyle)!); + obj.whammyStyle = (JsonHelper.parseEnum(v, BendStyle)!); return true; case "ottava": - obj.ottava = (r.enum(Ottavia)!); + obj.ottava = (JsonHelper.parseEnum(v, Ottavia)!); return true; case "islegatoorigin": - obj.isLegatoOrigin = (r.boolean()!); + obj.isLegatoOrigin = (v as boolean); return true; case "duration": - obj.duration = (r.enum(Duration)!); + obj.duration = (JsonHelper.parseEnum(v, Duration)!); return true; case "automations": obj.automations = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Automation(); - AutomationSerializer.fromJson(i, r) + AutomationSerializer.fromJson(i, o) obj.automations.push(i); } - r.endArray(); return true; case "dots": - obj.dots = (r.number()!); + obj.dots = (v as number); return true; case "fadein": - obj.fadeIn = (r.boolean()!); + obj.fadeIn = (v as boolean); return true; case "lyrics": - obj.lyrics = r.stringArray(); + obj.lyrics = (v as string[] | null); return true; case "hasrasgueado": - obj.hasRasgueado = (r.boolean()!); + obj.hasRasgueado = (v as boolean); return true; case "pop": - obj.pop = (r.boolean()!); + obj.pop = (v as boolean); return true; case "slap": - obj.slap = (r.boolean()!); + obj.slap = (v as boolean); return true; case "tap": - obj.tap = (r.boolean()!); + obj.tap = (v as boolean); return true; case "text": - obj.text = r.string(); + obj.text = (v as string | null); return true; case "brushtype": - obj.brushType = (r.enum(BrushType)!); + obj.brushType = (JsonHelper.parseEnum(v, BrushType)!); return true; case "brushduration": - obj.brushDuration = (r.number()!); + obj.brushDuration = (v as number); return true; case "tupletdenominator": - obj.tupletDenominator = (r.number()!); + obj.tupletDenominator = (v as number); return true; case "tupletnumerator": - obj.tupletNumerator = (r.number()!); + obj.tupletNumerator = (v as number); return true; case "iscontinuedwhammy": - obj.isContinuedWhammy = (r.boolean()!); + obj.isContinuedWhammy = (v as boolean); return true; case "whammybartype": - obj.whammyBarType = (r.enum(WhammyType)!); + obj.whammyBarType = (JsonHelper.parseEnum(v, WhammyType)!); return true; case "whammybarpoints": obj.whammyBarPoints = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new BendPoint(); - BendPointSerializer.fromJson(i, r) + BendPointSerializer.fromJson(i, o) obj.addWhammyBarPoint(i); } - r.endArray(); return true; case "vibrato": - obj.vibrato = (r.enum(VibratoType)!); + obj.vibrato = (JsonHelper.parseEnum(v, VibratoType)!); return true; case "chordid": - obj.chordId = r.string(); + obj.chordId = (v as string | null); return true; case "gracetype": - obj.graceType = (r.enum(GraceType)!); + obj.graceType = (JsonHelper.parseEnum(v, GraceType)!); return true; case "pickstroke": - obj.pickStroke = (r.enum(PickStroke)!); + obj.pickStroke = (JsonHelper.parseEnum(v, PickStroke)!); return true; case "tremolospeed": - obj.tremoloSpeed = r.enum(Duration); + obj.tremoloSpeed = JsonHelper.parseEnum(v, Duration); return true; case "crescendo": - obj.crescendo = (r.enum(CrescendoType)!); + obj.crescendo = (JsonHelper.parseEnum(v, CrescendoType)!); return true; case "displaystart": - obj.displayStart = (r.number()!); + obj.displayStart = (v as number); return true; case "playbackstart": - obj.playbackStart = (r.number()!); + obj.playbackStart = (v as number); return true; case "displayduration": - obj.displayDuration = (r.number()!); + obj.displayDuration = (v as number); return true; case "playbackduration": - obj.playbackDuration = (r.number()!); + obj.playbackDuration = (v as number); return true; case "dynamics": - obj.dynamics = (r.enum(DynamicValue)!); + obj.dynamics = (JsonHelper.parseEnum(v, DynamicValue)!); return true; case "invertbeamdirection": - obj.invertBeamDirection = (r.boolean()!); + obj.invertBeamDirection = (v as boolean); return true; case "preferredbeamdirection": - obj.preferredBeamDirection = r.enum(BeamDirection); + obj.preferredBeamDirection = JsonHelper.parseEnum(v, BeamDirection); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = (r.boolean()!); + obj.isEffectSlurOrigin = (v as boolean); return true; case "beamingmode": - obj.beamingMode = (r.enum(BeatBeamingMode)!); + obj.beamingMode = (JsonHelper.parseEnum(v, BeatBeamingMode)!); return true; } return false; diff --git a/src/generated/model/BendPointSerializer.ts b/src/generated/model/BendPointSerializer.ts index c9e51e8fc..b25834dc5 100644 --- a/src/generated/model/BendPointSerializer.ts +++ b/src/generated/model/BendPointSerializer.ts @@ -4,37 +4,30 @@ // the code is regenerated. // import { BendPoint } from "@src/model/BendPoint"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class BendPointSerializer { - public static fromJson(obj: BendPoint, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: BendPoint, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: BendPoint | null, w: JsonWriter): void { + public static toJson(obj: BendPoint | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.offset, "offset"); - w.number(obj.value, "value"); - w.endObject(); + const o = new Map(); + o.set("offset", obj.offset); + o.set("value", obj.value); + return o; } - public static setProperty(obj: BendPoint, property: string, r: JsonReader): boolean { + public static setProperty(obj: BendPoint, property: string, v: unknown): boolean { switch (property) { case "offset": - obj.offset = (r.number()!); + obj.offset = (v as number); return true; case "value": - obj.value = (r.number()!); + obj.value = (v as number); return true; } return false; diff --git a/src/generated/model/ChordSerializer.ts b/src/generated/model/ChordSerializer.ts index 7a2f9428b..a84a74163 100644 --- a/src/generated/model/ChordSerializer.ts +++ b/src/generated/model/ChordSerializer.ts @@ -4,57 +4,50 @@ // the code is regenerated. // import { Chord } from "@src/model/Chord"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class ChordSerializer { - public static fromJson(obj: Chord, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Chord, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Chord | null, w: JsonWriter): void { + public static toJson(obj: Chord | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.string(obj.name, "name"); - w.number(obj.firstFret, "firstFret"); - w.numberArray(obj.strings, "strings"); - w.numberArray(obj.barreFrets, "barreFrets"); - w.boolean(obj.showName, "showName"); - w.boolean(obj.showDiagram, "showDiagram"); - w.boolean(obj.showFingering, "showFingering"); - w.endObject(); + const o = new Map(); + o.set("name", obj.name); + o.set("firstFret", obj.firstFret); + o.set("strings", obj.strings); + o.set("barreFrets", obj.barreFrets); + o.set("showName", obj.showName); + o.set("showDiagram", obj.showDiagram); + o.set("showFingering", obj.showFingering); + return o; } - public static setProperty(obj: Chord, property: string, r: JsonReader): boolean { + public static setProperty(obj: Chord, property: string, v: unknown): boolean { switch (property) { case "name": - obj.name = (r.string()!); + obj.name = (v as string); return true; case "firstfret": - obj.firstFret = (r.number()!); + obj.firstFret = (v as number); return true; case "strings": - obj.strings = (r.numberArray()!); + obj.strings = (v as number[]); return true; case "barrefrets": - obj.barreFrets = (r.numberArray()!); + obj.barreFrets = (v as number[]); return true; case "showname": - obj.showName = (r.boolean()!); + obj.showName = (v as boolean); return true; case "showdiagram": - obj.showDiagram = (r.boolean()!); + obj.showDiagram = (v as boolean); return true; case "showfingering": - obj.showFingering = (r.boolean()!); + obj.showFingering = (v as boolean); return true; } return false; diff --git a/src/generated/model/FermataSerializer.ts b/src/generated/model/FermataSerializer.ts index 5aace2e09..2bbd8b5e0 100644 --- a/src/generated/model/FermataSerializer.ts +++ b/src/generated/model/FermataSerializer.ts @@ -4,38 +4,31 @@ // the code is regenerated. // import { Fermata } from "@src/model/Fermata"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { FermataType } from "@src/model/Fermata"; export class FermataSerializer { - public static fromJson(obj: Fermata, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Fermata, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Fermata | null, w: JsonWriter): void { + public static toJson(obj: Fermata | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.enum(obj.type, "type"); - w.number(obj.length, "length"); - w.endObject(); + const o = new Map(); + o.set("type", (obj.type as number)); + o.set("length", obj.length); + return o; } - public static setProperty(obj: Fermata, property: string, r: JsonReader): boolean { + public static setProperty(obj: Fermata, property: string, v: unknown): boolean { switch (property) { case "type": - obj.type = (r.enum(FermataType)!); + obj.type = (JsonHelper.parseEnum(v, FermataType)!); return true; case "length": - obj.length = (r.number()!); + obj.length = (v as number); return true; } return false; diff --git a/src/generated/model/InstrumentArticulationSerializer.ts b/src/generated/model/InstrumentArticulationSerializer.ts index 00332d659..88ba1d01c 100644 --- a/src/generated/model/InstrumentArticulationSerializer.ts +++ b/src/generated/model/InstrumentArticulationSerializer.ts @@ -4,59 +4,52 @@ // the code is regenerated. // import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { MusicFontSymbol } from "@src/model/MusicFontSymbol"; import { TextBaseline } from "@src/platform/ICanvas"; export class InstrumentArticulationSerializer { - public static fromJson(obj: InstrumentArticulation, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: InstrumentArticulation, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: InstrumentArticulation | null, w: JsonWriter): void { + public static toJson(obj: InstrumentArticulation | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.staffLine, "staffLine"); - w.enum(obj.noteHeadDefault, "noteHeadDefault"); - w.enum(obj.noteHeadHalf, "noteHeadHalf"); - w.enum(obj.noteHeadWhole, "noteHeadWhole"); - w.enum(obj.techniqueSymbol, "techniqueSymbol"); - w.enum(obj.techniqueSymbolPlacement, "techniqueSymbolPlacement"); - w.number(obj.outputMidiNumber, "outputMidiNumber"); - w.endObject(); + const o = new Map(); + o.set("staffLine", obj.staffLine); + o.set("noteHeadDefault", (obj.noteHeadDefault as number)); + o.set("noteHeadHalf", (obj.noteHeadHalf as number)); + o.set("noteHeadWhole", (obj.noteHeadWhole as number)); + o.set("techniqueSymbol", (obj.techniqueSymbol as number)); + o.set("techniqueSymbolPlacement", (obj.techniqueSymbolPlacement as number)); + o.set("outputMidiNumber", obj.outputMidiNumber); + return o; } - public static setProperty(obj: InstrumentArticulation, property: string, r: JsonReader): boolean { + public static setProperty(obj: InstrumentArticulation, property: string, v: unknown): boolean { switch (property) { case "staffline": - obj.staffLine = (r.number()!); + obj.staffLine = (v as number); return true; case "noteheaddefault": - obj.noteHeadDefault = (r.enum(MusicFontSymbol)!); + obj.noteHeadDefault = (JsonHelper.parseEnum(v, MusicFontSymbol)!); return true; case "noteheadhalf": - obj.noteHeadHalf = (r.enum(MusicFontSymbol)!); + obj.noteHeadHalf = (JsonHelper.parseEnum(v, MusicFontSymbol)!); return true; case "noteheadwhole": - obj.noteHeadWhole = (r.enum(MusicFontSymbol)!); + obj.noteHeadWhole = (JsonHelper.parseEnum(v, MusicFontSymbol)!); return true; case "techniquesymbol": - obj.techniqueSymbol = (r.enum(MusicFontSymbol)!); + obj.techniqueSymbol = (JsonHelper.parseEnum(v, MusicFontSymbol)!); return true; case "techniquesymbolplacement": - obj.techniqueSymbolPlacement = (r.enum(TextBaseline)!); + obj.techniqueSymbolPlacement = (JsonHelper.parseEnum(v, TextBaseline)!); return true; case "outputmidinumber": - obj.outputMidiNumber = (r.number()!); + obj.outputMidiNumber = (v as number); return true; } return false; diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index 22ee368dc..aaf90e63d 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -4,9 +4,7 @@ // the code is regenerated. // import { MasterBar } from "@src/model/MasterBar"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { SectionSerializer } from "@src/generated/model/SectionSerializer"; import { AutomationSerializer } from "@src/generated/model/AutomationSerializer"; import { FermataSerializer } from "@src/generated/model/FermataSerializer"; @@ -17,109 +15,93 @@ import { Section } from "@src/model/Section"; import { Automation } from "@src/model/Automation"; import { Fermata } from "@src/model/Fermata"; export class MasterBarSerializer { - public static fromJson(obj: MasterBar, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: MasterBar, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: MasterBar | null, w: JsonWriter): void { + public static toJson(obj: MasterBar | null): Map | null { if (!obj) { - w.null(); - return; + return null; + } + const o = new Map(); + o.set("alternateEndings", obj.alternateEndings); + o.set("index", obj.index); + o.set("keySignature", (obj.keySignature as number)); + o.set("keySignatureType", (obj.keySignatureType as number)); + o.set("isDoubleBar", obj.isDoubleBar); + o.set("isRepeatStart", obj.isRepeatStart); + o.set("repeatCount", obj.repeatCount); + o.set("timeSignatureNumerator", obj.timeSignatureNumerator); + o.set("timeSignatureDenominator", obj.timeSignatureDenominator); + o.set("timeSignatureCommon", obj.timeSignatureCommon); + o.set("tripletFeel", (obj.tripletFeel as number)); + o.set("section", SectionSerializer.toJson(obj.section)); + o.set("tempoAutomation", AutomationSerializer.toJson(obj.tempoAutomation)); + { + const m = new Map(); + o.set("fermata", m); + obj.fermata.forEach((v, k) => m.set(k.toString(), FermataSerializer.toJson(v))); } - w.startObject(); - w.number(obj.alternateEndings, "alternateEndings"); - w.number(obj.index, "index"); - w.enum(obj.keySignature, "keySignature"); - w.enum(obj.keySignatureType, "keySignatureType"); - w.boolean(obj.isDoubleBar, "isDoubleBar"); - w.boolean(obj.isRepeatStart, "isRepeatStart"); - w.number(obj.repeatCount, "repeatCount"); - w.number(obj.timeSignatureNumerator, "timeSignatureNumerator"); - w.number(obj.timeSignatureDenominator, "timeSignatureDenominator"); - w.boolean(obj.timeSignatureCommon, "timeSignatureCommon"); - w.enum(obj.tripletFeel, "tripletFeel"); - w.prop("section"); - if (obj.section) { - SectionSerializer.toJson(obj.section, w); - } - else - w.null(); - w.prop("tempoAutomation"); - if (obj.tempoAutomation) { - AutomationSerializer.toJson(obj.tempoAutomation, w); - } - else - w.null(); - w.prop("fermata"); - w.startObject(); - obj.fermata.forEach((v, k) => { w.prop(k); FermataSerializer.toJson(v, w); }); - w.endObject(); - w.number(obj.start, "start"); - w.boolean(obj.isAnacrusis, "isAnacrusis"); - w.endObject(); + o.set("start", obj.start); + o.set("isAnacrusis", obj.isAnacrusis); + return o; } - public static setProperty(obj: MasterBar, property: string, r: JsonReader): boolean { + public static setProperty(obj: MasterBar, property: string, v: unknown): boolean { switch (property) { case "alternateendings": - obj.alternateEndings = (r.number()!); + obj.alternateEndings = (v as number); return true; case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "keysignature": - obj.keySignature = (r.enum(KeySignature)!); + obj.keySignature = (JsonHelper.parseEnum(v, KeySignature)!); return true; case "keysignaturetype": - obj.keySignatureType = (r.enum(KeySignatureType)!); + obj.keySignatureType = (JsonHelper.parseEnum(v, KeySignatureType)!); return true; case "isdoublebar": - obj.isDoubleBar = (r.boolean()!); + obj.isDoubleBar = (v as boolean); return true; case "isrepeatstart": - obj.isRepeatStart = (r.boolean()!); + obj.isRepeatStart = (v as boolean); return true; case "repeatcount": - obj.repeatCount = (r.number()!); + obj.repeatCount = (v as number); return true; case "timesignaturenumerator": - obj.timeSignatureNumerator = (r.number()!); + obj.timeSignatureNumerator = (v as number); return true; case "timesignaturedenominator": - obj.timeSignatureDenominator = (r.number()!); + obj.timeSignatureDenominator = (v as number); return true; case "timesignaturecommon": - obj.timeSignatureCommon = (r.boolean()!); + obj.timeSignatureCommon = (v as boolean); return true; case "tripletfeel": - obj.tripletFeel = (r.enum(TripletFeel)!); + obj.tripletFeel = (JsonHelper.parseEnum(v, TripletFeel)!); return true; case "fermata": obj.fermata = new Map(); - r.startObject(); - while (r.nextProp()) { - const i = new Fermata(); - FermataSerializer.fromJson(i, r); - obj.fermata.set(r.numberProp(), i); - } - r.endObject(); + (v as Map).forEach((v, k) => { + const i = new Fermata(); + FermataSerializer.fromJson(i, (v as Map)); + obj.fermata.set(parseInt(k), i); + }); return true; case "start": - obj.start = (r.number()!); + obj.start = (v as number); return true; case "isanacrusis": - obj.isAnacrusis = (r.boolean()!); + obj.isAnacrusis = (v as boolean); return true; } if (["section"].indexOf(property) >= 0) { - if (r.currentValueType !== JsonValueType.Null) { + if (v) { obj.section = new Section(); - SectionSerializer.fromJson(obj.section, r); + SectionSerializer.fromJson(obj.section, (v as Map)); } else { obj.section = null; @@ -127,9 +109,9 @@ export class MasterBarSerializer { return true; } if (["tempoautomation"].indexOf(property) >= 0) { - if (r.currentValueType !== JsonValueType.Null) { + if (v) { obj.tempoAutomation = new Automation(); - AutomationSerializer.fromJson(obj.tempoAutomation, r); + AutomationSerializer.fromJson(obj.tempoAutomation, (v as Map)); } else { obj.tempoAutomation = null; diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index 1eaf2a7fe..798988bd5 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -4,9 +4,7 @@ // the code is regenerated. // import { Note } from "@src/model/Note"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { BendPointSerializer } from "@src/generated/model/BendPointSerializer"; import { AccentuationType } from "@src/model/AccentuationType"; import { BendType } from "@src/model/BendType"; @@ -21,209 +19,197 @@ import { Duration } from "@src/model/Duration"; import { NoteAccidentalMode } from "@src/model/NoteAccidentalMode"; import { DynamicValue } from "@src/model/DynamicValue"; export class NoteSerializer { - public static fromJson(obj: Note, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Note, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Note | null, w: JsonWriter): void { + public static toJson(obj: Note | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.number(obj.id, "id"); - w.number(obj.index, "index"); - w.enum(obj.accentuated, "accentuated"); - w.enum(obj.bendType, "bendType"); - w.enum(obj.bendStyle, "bendStyle"); - w.boolean(obj.isContinuedBend, "isContinuedBend"); - w.prop("bendPoints"); - w.startArray(); - for (const i of obj.bendPoints) { - BendPointSerializer.toJson(i, w); + return null; } - w.endArray(); - w.number(obj.fret, "fret"); - w.number(obj.string, "string"); - w.number(obj.octave, "octave"); - w.number(obj.tone, "tone"); - w.number(obj.percussionArticulation, "percussionArticulation"); - w.boolean(obj.isVisible, "isVisible"); - w.boolean(obj.isLeftHandTapped, "isLeftHandTapped"); - w.boolean(obj.isHammerPullOrigin, "isHammerPullOrigin"); - w.number(obj.hammerPullOriginNoteId, "hammerPullOriginNoteId"); - w.number(obj.hammerPullDestinationNoteId, "hammerPullDestinationNoteId"); - w.boolean(obj.isSlurDestination, "isSlurDestination"); - w.number(obj.slurOriginNoteId, "slurOriginNoteId"); - w.number(obj.slurDestinationNoteId, "slurDestinationNoteId"); - w.enum(obj.harmonicType, "harmonicType"); - w.number(obj.harmonicValue, "harmonicValue"); - w.boolean(obj.isGhost, "isGhost"); - w.boolean(obj.isLetRing, "isLetRing"); - w.boolean(obj.isPalmMute, "isPalmMute"); - w.boolean(obj.isDead, "isDead"); - w.boolean(obj.isStaccato, "isStaccato"); - w.enum(obj.slideInType, "slideInType"); - w.enum(obj.slideOutType, "slideOutType"); - w.enum(obj.vibrato, "vibrato"); - w.number(obj.tieOriginNoteId, "tieOriginNoteId"); - w.number(obj.tieDestinationNoteId, "tieDestinationNoteId"); - w.boolean(obj.isTieDestination, "isTieDestination"); - w.enum(obj.leftHandFinger, "leftHandFinger"); - w.enum(obj.rightHandFinger, "rightHandFinger"); - w.boolean(obj.isFingering, "isFingering"); - w.number(obj.trillValue, "trillValue"); - w.enum(obj.trillSpeed, "trillSpeed"); - w.number(obj.durationPercent, "durationPercent"); - w.enum(obj.accidentalMode, "accidentalMode"); - w.enum(obj.dynamics, "dynamics"); - w.boolean(obj.isEffectSlurOrigin, "isEffectSlurOrigin"); - w.boolean(obj.hasEffectSlur, "hasEffectSlur"); - w.endObject(); + const o = new Map(); + o.set("id", obj.id); + o.set("index", obj.index); + o.set("accentuated", (obj.accentuated as number)); + o.set("bendType", (obj.bendType as number)); + o.set("bendStyle", (obj.bendStyle as number)); + o.set("isContinuedBend", obj.isContinuedBend); + o.set("bendPoints", obj.bendPoints.map(i => BendPointSerializer.toJson(i))); + o.set("fret", obj.fret); + o.set("string", obj.string); + o.set("octave", obj.octave); + o.set("tone", obj.tone); + o.set("percussionArticulation", obj.percussionArticulation); + o.set("isVisible", obj.isVisible); + o.set("isLeftHandTapped", obj.isLeftHandTapped); + o.set("isHammerPullOrigin", obj.isHammerPullOrigin); + o.set("hammerPullOriginNoteId", obj.hammerPullOriginNoteId); + o.set("hammerPullDestinationNoteId", obj.hammerPullDestinationNoteId); + o.set("isSlurDestination", obj.isSlurDestination); + o.set("slurOriginNoteId", obj.slurOriginNoteId); + o.set("slurDestinationNoteId", obj.slurDestinationNoteId); + o.set("harmonicType", (obj.harmonicType as number)); + o.set("harmonicValue", obj.harmonicValue); + o.set("isGhost", obj.isGhost); + o.set("isLetRing", obj.isLetRing); + o.set("isPalmMute", obj.isPalmMute); + o.set("isDead", obj.isDead); + o.set("isStaccato", obj.isStaccato); + o.set("slideInType", (obj.slideInType as number)); + o.set("slideOutType", (obj.slideOutType as number)); + o.set("vibrato", (obj.vibrato as number)); + o.set("tieOriginNoteId", obj.tieOriginNoteId); + o.set("tieDestinationNoteId", obj.tieDestinationNoteId); + o.set("isTieDestination", obj.isTieDestination); + o.set("leftHandFinger", (obj.leftHandFinger as number)); + o.set("rightHandFinger", (obj.rightHandFinger as number)); + o.set("isFingering", obj.isFingering); + o.set("trillValue", obj.trillValue); + o.set("trillSpeed", (obj.trillSpeed as number)); + o.set("durationPercent", obj.durationPercent); + o.set("accidentalMode", (obj.accidentalMode as number)); + o.set("dynamics", (obj.dynamics as number)); + o.set("isEffectSlurOrigin", obj.isEffectSlurOrigin); + o.set("hasEffectSlur", obj.hasEffectSlur); + return o; } - public static setProperty(obj: Note, property: string, r: JsonReader): boolean { + public static setProperty(obj: Note, property: string, v: unknown): boolean { switch (property) { case "id": - obj.id = (r.number()!); + obj.id = (v as number); return true; case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "accentuated": - obj.accentuated = (r.enum(AccentuationType)!); + obj.accentuated = (JsonHelper.parseEnum(v, AccentuationType)!); return true; case "bendtype": - obj.bendType = (r.enum(BendType)!); + obj.bendType = (JsonHelper.parseEnum(v, BendType)!); return true; case "bendstyle": - obj.bendStyle = (r.enum(BendStyle)!); + obj.bendStyle = (JsonHelper.parseEnum(v, BendStyle)!); return true; case "iscontinuedbend": - obj.isContinuedBend = (r.boolean()!); + obj.isContinuedBend = (v as boolean); return true; case "bendpoints": obj.bendPoints = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new BendPoint(); - BendPointSerializer.fromJson(i, r) + BendPointSerializer.fromJson(i, o) obj.addBendPoint(i); } - r.endArray(); return true; case "fret": - obj.fret = (r.number()!); + obj.fret = (v as number); return true; case "string": - obj.string = (r.number()!); + obj.string = (v as number); return true; case "octave": - obj.octave = (r.number()!); + obj.octave = (v as number); return true; case "tone": - obj.tone = (r.number()!); + obj.tone = (v as number); return true; case "percussionarticulation": - obj.percussionArticulation = (r.number()!); + obj.percussionArticulation = (v as number); return true; case "isvisible": - obj.isVisible = (r.boolean()!); + obj.isVisible = (v as boolean); return true; case "islefthandtapped": - obj.isLeftHandTapped = (r.boolean()!); + obj.isLeftHandTapped = (v as boolean); return true; case "ishammerpullorigin": - obj.isHammerPullOrigin = (r.boolean()!); + obj.isHammerPullOrigin = (v as boolean); return true; case "hammerpulloriginnoteid": - obj.hammerPullOriginNoteId = (r.number()!); + obj.hammerPullOriginNoteId = (v as number); return true; case "hammerpulldestinationnoteid": - obj.hammerPullDestinationNoteId = (r.number()!); + obj.hammerPullDestinationNoteId = (v as number); return true; case "isslurdestination": - obj.isSlurDestination = (r.boolean()!); + obj.isSlurDestination = (v as boolean); return true; case "sluroriginnoteid": - obj.slurOriginNoteId = (r.number()!); + obj.slurOriginNoteId = (v as number); return true; case "slurdestinationnoteid": - obj.slurDestinationNoteId = (r.number()!); + obj.slurDestinationNoteId = (v as number); return true; case "harmonictype": - obj.harmonicType = (r.enum(HarmonicType)!); + obj.harmonicType = (JsonHelper.parseEnum(v, HarmonicType)!); return true; case "harmonicvalue": - obj.harmonicValue = (r.number()!); + obj.harmonicValue = (v as number); return true; case "isghost": - obj.isGhost = (r.boolean()!); + obj.isGhost = (v as boolean); return true; case "isletring": - obj.isLetRing = (r.boolean()!); + obj.isLetRing = (v as boolean); return true; case "ispalmmute": - obj.isPalmMute = (r.boolean()!); + obj.isPalmMute = (v as boolean); return true; case "isdead": - obj.isDead = (r.boolean()!); + obj.isDead = (v as boolean); return true; case "isstaccato": - obj.isStaccato = (r.boolean()!); + obj.isStaccato = (v as boolean); return true; case "slideintype": - obj.slideInType = (r.enum(SlideInType)!); + obj.slideInType = (JsonHelper.parseEnum(v, SlideInType)!); return true; case "slideouttype": - obj.slideOutType = (r.enum(SlideOutType)!); + obj.slideOutType = (JsonHelper.parseEnum(v, SlideOutType)!); return true; case "vibrato": - obj.vibrato = (r.enum(VibratoType)!); + obj.vibrato = (JsonHelper.parseEnum(v, VibratoType)!); return true; case "tieoriginnoteid": - obj.tieOriginNoteId = (r.number()!); + obj.tieOriginNoteId = (v as number); return true; case "tiedestinationnoteid": - obj.tieDestinationNoteId = (r.number()!); + obj.tieDestinationNoteId = (v as number); return true; case "istiedestination": - obj.isTieDestination = (r.boolean()!); + obj.isTieDestination = (v as boolean); return true; case "lefthandfinger": - obj.leftHandFinger = (r.enum(Fingers)!); + obj.leftHandFinger = (JsonHelper.parseEnum(v, Fingers)!); return true; case "righthandfinger": - obj.rightHandFinger = (r.enum(Fingers)!); + obj.rightHandFinger = (JsonHelper.parseEnum(v, Fingers)!); return true; case "isfingering": - obj.isFingering = (r.boolean()!); + obj.isFingering = (v as boolean); return true; case "trillvalue": - obj.trillValue = (r.number()!); + obj.trillValue = (v as number); return true; case "trillspeed": - obj.trillSpeed = (r.enum(Duration)!); + obj.trillSpeed = (JsonHelper.parseEnum(v, Duration)!); return true; case "durationpercent": - obj.durationPercent = (r.number()!); + obj.durationPercent = (v as number); return true; case "accidentalmode": - obj.accidentalMode = (r.enum(NoteAccidentalMode)!); + obj.accidentalMode = (JsonHelper.parseEnum(v, NoteAccidentalMode)!); return true; case "dynamics": - obj.dynamics = (r.enum(DynamicValue)!); + obj.dynamics = (JsonHelper.parseEnum(v, DynamicValue)!); return true; case "iseffectslurorigin": - obj.isEffectSlurOrigin = (r.boolean()!); + obj.isEffectSlurOrigin = (v as boolean); return true; case "haseffectslur": - obj.hasEffectSlur = (r.boolean()!); + obj.hasEffectSlur = (v as boolean); return true; } return false; diff --git a/src/generated/model/PlaybackInformationSerializer.ts b/src/generated/model/PlaybackInformationSerializer.ts index 59dabd05f..6cde5fde4 100644 --- a/src/generated/model/PlaybackInformationSerializer.ts +++ b/src/generated/model/PlaybackInformationSerializer.ts @@ -4,61 +4,54 @@ // the code is regenerated. // import { PlaybackInformation } from "@src/model/PlaybackInformation"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class PlaybackInformationSerializer { - public static fromJson(obj: PlaybackInformation, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: PlaybackInformation, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: PlaybackInformation | null, w: JsonWriter): void { + public static toJson(obj: PlaybackInformation | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.volume, "volume"); - w.number(obj.balance, "balance"); - w.number(obj.port, "port"); - w.number(obj.program, "program"); - w.number(obj.primaryChannel, "primaryChannel"); - w.number(obj.secondaryChannel, "secondaryChannel"); - w.boolean(obj.isMute, "isMute"); - w.boolean(obj.isSolo, "isSolo"); - w.endObject(); + const o = new Map(); + o.set("volume", obj.volume); + o.set("balance", obj.balance); + o.set("port", obj.port); + o.set("program", obj.program); + o.set("primaryChannel", obj.primaryChannel); + o.set("secondaryChannel", obj.secondaryChannel); + o.set("isMute", obj.isMute); + o.set("isSolo", obj.isSolo); + return o; } - public static setProperty(obj: PlaybackInformation, property: string, r: JsonReader): boolean { + public static setProperty(obj: PlaybackInformation, property: string, v: unknown): boolean { switch (property) { case "volume": - obj.volume = (r.number()!); + obj.volume = (v as number); return true; case "balance": - obj.balance = (r.number()!); + obj.balance = (v as number); return true; case "port": - obj.port = (r.number()!); + obj.port = (v as number); return true; case "program": - obj.program = (r.number()!); + obj.program = (v as number); return true; case "primarychannel": - obj.primaryChannel = (r.number()!); + obj.primaryChannel = (v as number); return true; case "secondarychannel": - obj.secondaryChannel = (r.number()!); + obj.secondaryChannel = (v as number); return true; case "ismute": - obj.isMute = (r.boolean()!); + obj.isMute = (v as boolean); return true; case "issolo": - obj.isSolo = (r.boolean()!); + obj.isSolo = (v as boolean); return true; } return false; diff --git a/src/generated/model/RenderStylesheetSerializer.ts b/src/generated/model/RenderStylesheetSerializer.ts index de5b901f9..d2fcaf542 100644 --- a/src/generated/model/RenderStylesheetSerializer.ts +++ b/src/generated/model/RenderStylesheetSerializer.ts @@ -4,33 +4,26 @@ // the code is regenerated. // import { RenderStylesheet } from "@src/model/RenderStylesheet"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class RenderStylesheetSerializer { - public static fromJson(obj: RenderStylesheet, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: RenderStylesheet, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: RenderStylesheet | null, w: JsonWriter): void { + public static toJson(obj: RenderStylesheet | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.boolean(obj.hideDynamics, "hideDynamics"); - w.endObject(); + const o = new Map(); + o.set("hideDynamics", obj.hideDynamics); + return o; } - public static setProperty(obj: RenderStylesheet, property: string, r: JsonReader): boolean { + public static setProperty(obj: RenderStylesheet, property: string, v: unknown): boolean { switch (property) { case "hidedynamics": - obj.hideDynamics = (r.boolean()!); + obj.hideDynamics = (v as boolean); return true; } return false; diff --git a/src/generated/model/ScoreSerializer.ts b/src/generated/model/ScoreSerializer.ts index 1ff650dfa..474ac516d 100644 --- a/src/generated/model/ScoreSerializer.ts +++ b/src/generated/model/ScoreSerializer.ts @@ -4,120 +4,98 @@ // the code is regenerated. // import { Score } from "@src/model/Score"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { MasterBarSerializer } from "@src/generated/model/MasterBarSerializer"; import { TrackSerializer } from "@src/generated/model/TrackSerializer"; import { RenderStylesheetSerializer } from "@src/generated/model/RenderStylesheetSerializer"; import { MasterBar } from "@src/model/MasterBar"; import { Track } from "@src/model/Track"; export class ScoreSerializer { - public static fromJson(obj: Score, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Score, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Score | null, w: JsonWriter): void { + public static toJson(obj: Score | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.string(obj.album, "album"); - w.string(obj.artist, "artist"); - w.string(obj.copyright, "copyright"); - w.string(obj.instructions, "instructions"); - w.string(obj.music, "music"); - w.string(obj.notices, "notices"); - w.string(obj.subTitle, "subTitle"); - w.string(obj.title, "title"); - w.string(obj.words, "words"); - w.string(obj.tab, "tab"); - w.number(obj.tempo, "tempo"); - w.string(obj.tempoLabel, "tempoLabel"); - w.prop("masterBars"); - w.startArray(); - for (const i of obj.masterBars) { - MasterBarSerializer.toJson(i, w); - } - w.endArray(); - w.prop("tracks"); - w.startArray(); - for (const i of obj.tracks) { - TrackSerializer.toJson(i, w); + return null; } - w.endArray(); - w.prop("stylesheet"); - RenderStylesheetSerializer.toJson(obj.stylesheet, w); - w.endObject(); + const o = new Map(); + o.set("album", obj.album); + o.set("artist", obj.artist); + o.set("copyright", obj.copyright); + o.set("instructions", obj.instructions); + o.set("music", obj.music); + o.set("notices", obj.notices); + o.set("subTitle", obj.subTitle); + o.set("title", obj.title); + o.set("words", obj.words); + o.set("tab", obj.tab); + o.set("tempo", obj.tempo); + o.set("tempoLabel", obj.tempoLabel); + o.set("masterBars", obj.masterBars.map(i => MasterBarSerializer.toJson(i))); + o.set("tracks", obj.tracks.map(i => TrackSerializer.toJson(i))); + o.set("stylesheet", RenderStylesheetSerializer.toJson(obj.stylesheet)); + return o; } - public static setProperty(obj: Score, property: string, r: JsonReader): boolean { + public static setProperty(obj: Score, property: string, v: unknown): boolean { switch (property) { case "album": - obj.album = (r.string()!); + obj.album = (v as string); return true; case "artist": - obj.artist = (r.string()!); + obj.artist = (v as string); return true; case "copyright": - obj.copyright = (r.string()!); + obj.copyright = (v as string); return true; case "instructions": - obj.instructions = (r.string()!); + obj.instructions = (v as string); return true; case "music": - obj.music = (r.string()!); + obj.music = (v as string); return true; case "notices": - obj.notices = (r.string()!); + obj.notices = (v as string); return true; case "subtitle": - obj.subTitle = (r.string()!); + obj.subTitle = (v as string); return true; case "title": - obj.title = (r.string()!); + obj.title = (v as string); return true; case "words": - obj.words = (r.string()!); + obj.words = (v as string); return true; case "tab": - obj.tab = (r.string()!); + obj.tab = (v as string); return true; case "tempo": - obj.tempo = (r.number()!); + obj.tempo = (v as number); return true; case "tempolabel": - obj.tempoLabel = (r.string()!); + obj.tempoLabel = (v as string); return true; case "masterbars": obj.masterBars = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new MasterBar(); - MasterBarSerializer.fromJson(i, r) + MasterBarSerializer.fromJson(i, o) obj.addMasterBar(i); } - r.endArray(); return true; case "tracks": obj.tracks = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Track(); - TrackSerializer.fromJson(i, r) + TrackSerializer.fromJson(i, o) obj.addTrack(i); } - r.endArray(); return true; } if (["stylesheet"].indexOf(property) >= 0) { - RenderStylesheetSerializer.fromJson(obj.stylesheet, r); + RenderStylesheetSerializer.fromJson(obj.stylesheet, (v as Map)); return true; } return false; diff --git a/src/generated/model/SectionSerializer.ts b/src/generated/model/SectionSerializer.ts index 3ca086c7e..c5c82f271 100644 --- a/src/generated/model/SectionSerializer.ts +++ b/src/generated/model/SectionSerializer.ts @@ -4,37 +4,30 @@ // the code is regenerated. // import { Section } from "@src/model/Section"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; export class SectionSerializer { - public static fromJson(obj: Section, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Section, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Section | null, w: JsonWriter): void { + public static toJson(obj: Section | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.string(obj.marker, "marker"); - w.string(obj.text, "text"); - w.endObject(); + const o = new Map(); + o.set("marker", obj.marker); + o.set("text", obj.text); + return o; } - public static setProperty(obj: Section, property: string, r: JsonReader): boolean { + public static setProperty(obj: Section, property: string, v: unknown): boolean { switch (property) { case "marker": - obj.marker = (r.string()!); + obj.marker = (v as string); return true; case "text": - obj.text = (r.string()!); + obj.text = (v as string); return true; } return false; diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 6742af864..64db41406 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -4,103 +4,88 @@ // the code is regenerated. // import { Staff } from "@src/model/Staff"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { BarSerializer } from "@src/generated/model/BarSerializer"; import { ChordSerializer } from "@src/generated/model/ChordSerializer"; import { Bar } from "@src/model/Bar"; import { Chord } from "@src/model/Chord"; export class StaffSerializer { - public static fromJson(obj: Staff, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Staff, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Staff | null, w: JsonWriter): void { + public static toJson(obj: Staff | null): Map | null { if (!obj) { - w.null(); - return; + return null; } - w.startObject(); - w.number(obj.index, "index"); - w.prop("bars"); - w.startArray(); - for (const i of obj.bars) { - BarSerializer.toJson(i, w); + const o = new Map(); + o.set("index", obj.index); + o.set("bars", obj.bars.map(i => BarSerializer.toJson(i))); + { + const m = new Map(); + o.set("chords", m); + obj.chords.forEach((v, k) => m.set(k.toString(), ChordSerializer.toJson(v))); } - w.endArray(); - w.prop("chords"); - w.startObject(); - obj.chords.forEach((v, k) => { w.prop(k); ChordSerializer.toJson(v, w); }); - w.endObject(); - w.number(obj.capo, "capo"); - w.number(obj.transpositionPitch, "transpositionPitch"); - w.number(obj.displayTranspositionPitch, "displayTranspositionPitch"); - w.numberArray(obj.tuning, "tuning"); - w.string(obj.tuningName, "tuningName"); - w.boolean(obj.showTablature, "showTablature"); - w.boolean(obj.showStandardNotation, "showStandardNotation"); - w.boolean(obj.isPercussion, "isPercussion"); - w.number(obj.standardNotationLineCount, "standardNotationLineCount"); - w.endObject(); + o.set("capo", obj.capo); + o.set("transpositionPitch", obj.transpositionPitch); + o.set("displayTranspositionPitch", obj.displayTranspositionPitch); + o.set("tuning", obj.tuning); + o.set("tuningName", obj.tuningName); + o.set("showTablature", obj.showTablature); + o.set("showStandardNotation", obj.showStandardNotation); + o.set("isPercussion", obj.isPercussion); + o.set("standardNotationLineCount", obj.standardNotationLineCount); + return o; } - public static setProperty(obj: Staff, property: string, r: JsonReader): boolean { + public static setProperty(obj: Staff, property: string, v: unknown): boolean { switch (property) { case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "bars": obj.bars = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Bar(); - BarSerializer.fromJson(i, r) + BarSerializer.fromJson(i, o) obj.addBar(i); } - r.endArray(); return true; case "chords": obj.chords = new Map(); - r.startObject(); - while (r.nextProp()) { - const i = new Chord(); - ChordSerializer.fromJson(i, r); - obj.addChord(r.prop(), i); - } - r.endObject(); + (v as Map).forEach((v, k) => { + const i = new Chord(); + ChordSerializer.fromJson(i, (v as Map)); + obj.addChord(k, i); + }); return true; case "capo": - obj.capo = (r.number()!); + obj.capo = (v as number); return true; case "transpositionpitch": - obj.transpositionPitch = (r.number()!); + obj.transpositionPitch = (v as number); return true; case "displaytranspositionpitch": - obj.displayTranspositionPitch = (r.number()!); + obj.displayTranspositionPitch = (v as number); return true; case "tuning": - obj.tuning = (r.numberArray()!); + obj.tuning = (v as number[]); return true; case "tuningname": - obj.tuningName = (r.string()!); + obj.tuningName = (v as string); return true; case "showtablature": - obj.showTablature = (r.boolean()!); + obj.showTablature = (v as boolean); return true; case "showstandardnotation": - obj.showStandardNotation = (r.boolean()!); + obj.showStandardNotation = (v as boolean); return true; case "ispercussion": - obj.isPercussion = (r.boolean()!); + obj.isPercussion = (v as boolean); return true; case "standardnotationlinecount": - obj.standardNotationLineCount = (r.number()!); + obj.standardNotationLineCount = (v as number); return true; } return false; diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index 1e160a097..fb0efcd82 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -4,9 +4,7 @@ // the code is regenerated. // import { Track } from "@src/model/Track"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { StaffSerializer } from "@src/generated/model/StaffSerializer"; import { PlaybackInformationSerializer } from "@src/generated/model/PlaybackInformationSerializer"; import { Color } from "@src/model/Color"; @@ -14,80 +12,59 @@ import { InstrumentArticulationSerializer } from "@src/generated/model/Instrumen import { Staff } from "@src/model/Staff"; import { InstrumentArticulation } from "@src/model/InstrumentArticulation"; export class TrackSerializer { - public static fromJson(obj: Track, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Track, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Track | null, w: JsonWriter): void { + public static toJson(obj: Track | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.number(obj.index, "index"); - w.prop("staves"); - w.startArray(); - for (const i of obj.staves) { - StaffSerializer.toJson(i, w); - } - w.endArray(); - w.prop("playbackInfo"); - PlaybackInformationSerializer.toJson(obj.playbackInfo, w); - w.prop("color"); - Color.toJson(obj.color, w); - w.string(obj.name, "name"); - w.string(obj.shortName, "shortName"); - w.prop("percussionArticulations"); - w.startArray(); - for (const i of obj.percussionArticulations) { - InstrumentArticulationSerializer.toJson(i, w); + return null; } - w.endArray(); - w.endObject(); + const o = new Map(); + o.set("index", obj.index); + o.set("staves", obj.staves.map(i => StaffSerializer.toJson(i))); + o.set("playbackInfo", PlaybackInformationSerializer.toJson(obj.playbackInfo)); + o.set("color", Color.toJson(obj.color)); + o.set("name", obj.name); + o.set("shortName", obj.shortName); + o.set("percussionArticulations", obj.percussionArticulations.map(i => InstrumentArticulationSerializer.toJson(i))); + return o; } - public static setProperty(obj: Track, property: string, r: JsonReader): boolean { + public static setProperty(obj: Track, property: string, v: unknown): boolean { switch (property) { case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "staves": obj.staves = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Staff(); - StaffSerializer.fromJson(i, r) + StaffSerializer.fromJson(i, o) obj.addStaff(i); } - r.endArray(); return true; case "color": - obj.color = (Color.fromJson(r)!); + obj.color = (Color.fromJson(v)!); return true; case "name": - obj.name = (r.string()!); + obj.name = (v as string); return true; case "shortname": - obj.shortName = (r.string()!); + obj.shortName = (v as string); return true; case "percussionarticulations": obj.percussionArticulations = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new InstrumentArticulation(); - InstrumentArticulationSerializer.fromJson(i, r) + InstrumentArticulationSerializer.fromJson(i, o) obj.percussionArticulations.push(i); } - r.endArray(); return true; } if (["playbackinfo"].indexOf(property) >= 0) { - PlaybackInformationSerializer.fromJson(obj.playbackInfo, r); + PlaybackInformationSerializer.fromJson(obj.playbackInfo, (v as Map)); return true; } return false; diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index f04692e20..cf29dadbe 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -4,55 +4,41 @@ // the code is regenerated. // import { Voice } from "@src/model/Voice"; -import { JsonReader } from "@src/io/JsonReader"; -import { JsonValueType } from "@src/io/JsonReader"; -import { JsonWriter } from "@src/io/JsonWriter"; +import { JsonHelper } from "@src/io/JsonHelper"; import { BeatSerializer } from "@src/generated/model/BeatSerializer"; import { Beat } from "@src/model/Beat"; export class VoiceSerializer { - public static fromJson(obj: Voice, r: JsonReader): void { - if (r.currentValueType === JsonValueType.Null) { + public static fromJson(obj: Voice, m: unknown): void { + if (!m) { return; } - r.startObject(); - while (r.nextProp()) { - this.setProperty(obj, r.prop().toLowerCase(), r); - } - r.endObject(); + JsonHelper.forEach(m, (v, k) => this.setProperty(obj, k.toLowerCase(), v)); } - public static toJson(obj: Voice | null, w: JsonWriter): void { + public static toJson(obj: Voice | null): Map | null { if (!obj) { - w.null(); - return; - } - w.startObject(); - w.number(obj.index, "index"); - w.prop("beats"); - w.startArray(); - for (const i of obj.beats) { - BeatSerializer.toJson(i, w); + return null; } - w.endArray(); - w.boolean(obj.isEmpty, "isEmpty"); - w.endObject(); + const o = new Map(); + o.set("index", obj.index); + o.set("beats", obj.beats.map(i => BeatSerializer.toJson(i))); + o.set("isEmpty", obj.isEmpty); + return o; } - public static setProperty(obj: Voice, property: string, r: JsonReader): boolean { + public static setProperty(obj: Voice, property: string, v: unknown): boolean { switch (property) { case "index": - obj.index = (r.number()!); + obj.index = (v as number); return true; case "beats": obj.beats = []; - r.startArray(); - while (r.nextItem()) { + for (const o of (v as (Map | null)[])) { const i = new Beat(); - BeatSerializer.fromJson(i, r) + BeatSerializer.fromJson(i, o) obj.addBeat(i); } - r.endArray(); return true; case "isempty": - obj.isEmpty = (r.boolean()!); + obj.isEmpty = (v as boolean); return true; } return false; diff --git a/src/io/JsonHelper.ts b/src/io/JsonHelper.ts new file mode 100644 index 000000000..85599a782 --- /dev/null +++ b/src/io/JsonHelper.ts @@ -0,0 +1,40 @@ +import { AlphaTabError } from "@src/alphatab"; +import { AlphaTabErrorType } from "@src/AlphaTabError"; + +/** + * @partial + */ +export class JsonHelper { + /** + * @target web + */ + public static parseEnum(s: unknown, enumType: any): T | null { + switch (typeof s) { + case 'string': + const num = parseInt(s); + return isNaN(num) + ? enumType[Object.keys(enumType).find(k => k.toLowerCase() === s.toLowerCase()) as any] as any + : num as unknown as T; + case 'number': + return s as unknown as T; + case 'undefined': + case 'object': + return null; + } + throw new AlphaTabError(AlphaTabErrorType.Format, `Could not parse enum value '${s}'`); + } + + /** + * @target web + */ + public static forEach(s: unknown, func: (v: unknown, k: string) => void): void { + if (s instanceof Map) { + (s as Map).forEach(func); + }else if (typeof s === 'object') { + for (const k in s) { + func((s as any)[k], k) + } + } + // skip + } +} \ No newline at end of file diff --git a/src/io/JsonReader.ts b/src/io/JsonReader.ts deleted file mode 100644 index 3771b1cc9..000000000 --- a/src/io/JsonReader.ts +++ /dev/null @@ -1,323 +0,0 @@ -/** - * Lists the different data types JSON properties can have. - */ -export enum JsonValueType { - /** - * The json value is a simple string. - */ - String, - /** - * The json value is a number. - */ - Number, - /** - * The json value is a boolean. - */ - Boolean, - /** - * The json value is null. - */ - Null, - /** - * The json value is a nested object. - */ - Object, - /** - * The json value is a nested array. - */ - Array -} - -/** - * @partial - */ -class ReaderStackItem { - public obj: unknown; - public currentIndex: number = -1; - - // for object iteration - public currentProp: string = ''; - public currentValue: unknown = null; - - public currentObjectKeys: string[]; - - public constructor(obj: unknown) { - if (obj) { - if (Array.isArray(obj)) { - this.currentObjectKeys = []; - } else { - if (!(obj instanceof Map)) { - obj = ReaderStackItem.objectToMap(obj as object); - } - this.currentObjectKeys = Array.from((obj as Map).keys()); - } - } else { - this.currentObjectKeys = []; - } - - - this.obj = obj; - } - - /** - * @target web - */ - private static objectToMap(obj: object | null): Map { - return new Map(Object.entries(obj as any)) - } -} - -/** - * Represents a data reader to read data structures from a JSON-alike source structure. - * @partial - */ -export class JsonReader { - private _currentItem: ReaderStackItem | null = null; - private _readStack: ReaderStackItem[] = []; - - /** - * Gets the data type of the current item at which the reader is placed. - * This is usually either the current property of an object or the current item in an array. - */ - public currentValueType: JsonValueType = JsonValueType.Null; - - public constructor(root: any) { - const map = new Map(); - map.set("root", root); - this.setCurrentObject(map); - this.nextProp(); - } - - /** - * Reads the current object property name as string. - * Requires that an object is currently being read. - */ - public prop(): string { - return this._currentItem?.currentProp ?? ""; - } - - /** - * Reads the current object property name as enum value. - * This works for either number or string based keys. - * @param enumType The type of the enum which defines the values of T - */ - public enumProp(enumType: unknown): T { - const prop = this.prop(); - const num = parseInt(prop); - return isNaN(num) - ? this.parseEnum(prop, enumType) - : num as unknown as T; - } - - /** - * Reads the current object property as number value. - */ - public numberProp(): number { - const prop = this.prop(); - return parseInt(prop); - } - - /** - * Advances the reader to the next property within the currently read object. - */ - public nextProp(): boolean { - const currentItem = this._currentItem!; - currentItem.currentIndex++; - if (currentItem.currentIndex < currentItem.currentObjectKeys.length) { - currentItem.currentProp = currentItem.currentObjectKeys[currentItem.currentIndex]; - currentItem.currentValue = (currentItem.obj as Map).get(currentItem.currentProp); - this.updateCurrentValueType(currentItem.currentValue); - return true; - } else { - this.currentValueType = JsonValueType.Null; - return false; - } - } - - /** - * Advances the reader to the next item within the currently read array. - */ - public nextItem(): boolean { - const currentItem = this._currentItem!; - currentItem.currentIndex++; - - if (Array.isArray(currentItem.obj) && - currentItem.currentIndex < (currentItem.obj as any[]).length) { - currentItem.currentValue = (currentItem.obj as any[])[currentItem.currentIndex]; - this.updateCurrentValueType(currentItem.currentValue); - return true; - } else { - return false; - } - } - - /** - * Starts reading of a nested object. - */ - public startObject(): void { - const currentItem = this._currentItem; - if (currentItem) { - switch (this.currentValueType) { - case JsonValueType.Object: - this.setCurrentObject(currentItem.currentValue!); - break; - case JsonValueType.Array: - this.setCurrentObject(currentItem.currentValue!); - break; - default: - throw new Error(`Cannot start object/array in the current item. item is a ${JsonValueType[this.currentValueType]}`); - } - } - } - - /** - * Completes the reading of a nested object. - */ - public endObject(): void { - this._readStack.pop(); - this._currentItem = this._readStack[this._readStack.length - 1]; - } - - /** - * Starts the reading of a nested array. - */ - public startArray(): void { - this.startObject(); - } - - /** - * Completes the reading of a nested array. - */ - public endArray(): void { - this.endObject(); - } - - /** - * Reads the current property value as a raw unknown value without further parsing. - * @returns the current raw property value - */ - public unknown(): unknown { - return this.value(this.currentValueType); - } - - /** - * Reads the current property value as string. - * @returns the current property value if it is a string or null if it is a different type. - */ - public string(): string | null { - return this.value(JsonValueType.String); - } - - /** - * Reads the current property value as enum. - * Number and case-insenstive strings are supported. - * @returns the current property value as enum or null if it could not be parsed. - */ - public enum(enumType: any): T | null { - const currentItem = this._currentItem; - if (currentItem) { - switch (this.currentValueType) { - case JsonValueType.String: - return this.parseEnum(currentItem.currentValue as string, enumType); - case JsonValueType.Number: - return this.numberToEnum(currentItem.currentValue as number); - } - } - return null; - } - - /** - * Reads the current property value as number. - * @returns the current property value if it is a number or null if it is a different type. - */ - public number(): number | null { - return this.valueStruct(JsonValueType.Number); - } - - /** - * Reads the current property value as boolean. - * @returns the current property value if it is a boolean or null if it is a different type. - */ - public boolean(): boolean | null { - return this.valueStruct(JsonValueType.Boolean); - } - - /** - * Reads the current property value as string array. - * @returns the current property value if it is an array or null if it is a different type. - */ - public stringArray(): string[] | null { - return this.value(JsonValueType.Array); - } - - /** - * Reads the current property value as number array. - * @returns the current property value if it is an array or null if it is a different type. - */ - public numberArray(): number[] | null { - return this.value(JsonValueType.Array); - } - - private updateCurrentValueType(val: any) { - switch (typeof val) { - case 'undefined': - this.currentValueType = JsonValueType.Null; - break; - case 'string': - this.currentValueType = JsonValueType.String; - break; - case 'object': - if (val === null) { - this.currentValueType = JsonValueType.Null; - } else if (Array.isArray(val)) { - this.currentValueType = JsonValueType.Array; - } else { - this.currentValueType = JsonValueType.Object; - } - break; - case 'number': - this.currentValueType = JsonValueType.Number; - break; - case 'boolean': - this.currentValueType = JsonValueType.Boolean; - break; - } - } - - private setCurrentObject(current: any) { - const obj = new ReaderStackItem(current); - this._readStack.push(obj); - this._currentItem = obj; - } - - // required for C# generation where nullable struct/classes need separate methods - private valueStruct(type: JsonValueType): T | null { - const currentItem = this._currentItem; - if (currentItem && this.currentValueType === type) { - return currentItem.currentValue as T; - } - return null; - } - - private value(type: JsonValueType): T | null { - const currentItem = this._currentItem; - if (currentItem && this.currentValueType === type) { - return currentItem.currentValue as T; - } - return null; - } - - /** - * @target web - */ - private parseEnum(value: string, enumType: any): T { - return enumType[Object.keys(enumType).find(k => k.toLowerCase() === value.toLowerCase()) as any] as any; - } - - /** - * @target web - */ - private numberToEnum(value: number): T { - return value as unknown as T; - } -} \ No newline at end of file diff --git a/src/io/JsonWriter.ts b/src/io/JsonWriter.ts deleted file mode 100644 index 7223aea10..000000000 --- a/src/io/JsonWriter.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { AlphaTabError } from "@src/alphatab"; -import { AlphaTabErrorType } from "@src/AlphaTabError"; - -/** - * Represents a data writer to write data structures into a JSON-alike object hierarchy for further serialization. - * @partial - */ -export class JsonWriter { - private _objectStack: unknown[] = []; - private _currentPropertyName: string = ''; - - public result: Map | null = null; - - public startObject(): void { - if (this._objectStack.length > 0) { - const newObject = new Map(); - const currentObject = this._objectStack[this._objectStack.length - 1]; - this._objectStack.push(newObject); - - if (Array.isArray(currentObject)) { - currentObject.push(newObject); - } else { - (currentObject as Map).set(this._currentPropertyName, newObject); - } - } else { - this.result = new Map(); - this._objectStack.push(this.result); - } - } - - public endObject(): void { - this._objectStack.pop(); - } - - public startArray(): void { - if (this._objectStack.length > 0) { - const newObject: unknown[] = []; - const currentObject = this._objectStack[this._objectStack.length - 1]; - this._objectStack.push(newObject); - - if (Array.isArray(currentObject)) { - currentObject.push(newObject); - } else { - (currentObject as Map).set(this._currentPropertyName, newObject); - } - } else { - throw new AlphaTabError(AlphaTabErrorType.General, 'Root object to be serialized cannot be an array'); - } - } - - public endArray(): void { - this._objectStack.pop(); - } - - public prop(name: unknown): void { - this._currentPropertyName = (name as object).toString(); - } - - public unknown(value: unknown, propName?: unknown): void { - this.writeValue(value, propName); - } - - public string(value: string | null, propName?: unknown): void { - this.writeValue(value, propName); - } - - public number(value: number | null, propName?: unknown): void { - this.writeValue(value, propName); - } - - public boolean(value: boolean | null, propName?: unknown): void { - this.writeValue(value, propName); - } - - public enum(value: T, propName?: unknown): void { - this.writeValue(this.enumToNumber(value), propName); - } - - public null(propName?: unknown): void { - this.writeValue(null, propName); - } - - public stringArray(value: string[] | null, propName?: unknown): void { - this.writeValue(value, propName); - } - - public numberArray(value: number[] | null, propName?: unknown): void { - this.writeValue(value, propName); - } - - private writeValue(value: any, propName?: unknown) { - if (this._objectStack.length > 0) { - const currentObject = this._objectStack[this._objectStack.length - 1]; - if (Array.isArray(currentObject)) { - this._objectStack.push(value); - } else { - if (typeof propName === 'undefined') { - propName = this._currentPropertyName; - } - (currentObject as Map).set((propName as object).toString(), value); - } - } else { - throw new AlphaTabError(AlphaTabErrorType.General, 'Root object to be serialized cannot be a plain value'); - } - } - - /** - * @target web - */ - private enumToNumber(value: T): number | null { - return value as unknown as number; - } -} \ No newline at end of file diff --git a/src/model/Color.ts b/src/model/Color.ts index 73cbb535e..e247a4260 100644 --- a/src/model/Color.ts +++ b/src/model/Color.ts @@ -1,6 +1,4 @@ import { FormatError } from '@src/FormatError'; -import { JsonReader, JsonValueType } from '@src/io/JsonReader'; -import { JsonWriter } from '@src/io/JsonWriter'; import { ModelUtils } from './ModelUtils'; /** @@ -64,18 +62,18 @@ export class Color { return new Color((Math.random() * 255) | 0, (Math.random() * 255) | 0, (Math.random() * 255) | 0, opacity); } - public static fromJson(reader: JsonReader): Color | null { - switch (reader.currentValueType) { - case JsonValueType.Number: + public static fromJson(v: unknown): Color | null { + switch (typeof v) { + case 'number': { const c = new Color(0, 0, 0, 0); - c.raw = reader.number()!; + c.raw = v as number; c.updateRgba(); return c; } - case JsonValueType.String: + case 'string': { - const json = reader.string()!; + const json = v as string; if (json.startsWith('#')) { if (json.length === 4) { // #RGB @@ -142,7 +140,7 @@ export class Color { throw new FormatError('Unsupported format for color'); } - public static toJson(obj: Color, writer: JsonWriter): void { - writer.number(obj.raw); + public static toJson(obj: Color): number { + return obj.raw; } } diff --git a/src/model/Font.ts b/src/model/Font.ts index 2571cfd4f..1af1f2468 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -1,5 +1,4 @@ -import { JsonReader, JsonValueType } from '@src/io/JsonReader'; -import { JsonWriter } from '@src/io/JsonWriter'; +import { JsonHelper } from '@src/io/JsonHelper'; /** * A very basic font parser which parses the fields according to @@ -339,35 +338,21 @@ export class Font { return this._css; } - public static fromJson(reader: JsonReader): Font | null { - switch (reader.currentValueType) { - case JsonValueType.Null: + public static fromJson(v:unknown): Font | null { + switch (typeof v) { + case 'undefined': return null; - case JsonValueType.Object: + case 'object': { - let family = ''; - let size = 0; - let style = FontStyle.Plain; - reader.startObject(); - while (reader.nextProp()) { - switch (reader.prop().toLowerCase()) { - case 'family': - family = reader.string()!; - break; - case 'size': - size = reader.number()!; - break; - case 'style': - style = reader.enum(FontStyle)!; - break; - } - } - reader.endObject(); + const m = v as Map; + let family = m.get('family') as string; + let size = m.get('size') as number; + let style = JsonHelper.parseEnum(m.get('style'), FontStyle)!; return new Font(family, size, style); } - case JsonValueType.String: + case 'string': { - const parser = new FontParser(reader.string()!); + const parser = new FontParser(v as string); parser.parse(); let family: string = parser.families[0]; @@ -440,11 +425,11 @@ export class Font { } } - public static toJson(font: Font, writer: JsonWriter): void { - writer.startObject(); - writer.string(font.family, 'family'); - writer.number(font.size, 'size'); - writer.number(font.style, 'style'); - writer.endObject(); + public static toJson(font: Font): Map { + const o = new Map(); + o.set('family', font.family); + o.set('size', font.size); + o.set('style', font.style as number); + return o; } } diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index c9197c7ca..c84967304 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -7,8 +7,6 @@ import { Score } from '@src/model/Score'; import { Settings } from '@src/Settings'; import { Midi20PerNotePitchBendEvent } from '@src/midi/Midi20ChannelVoiceEvent'; import { ScoreSerializer } from '@src/generated/model/ScoreSerializer'; -import { JsonReader } from '@src/io/JsonReader'; -import { JsonWriter } from '@src/io/JsonWriter'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** @@ -39,9 +37,7 @@ export class JsonConverter { * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. */ public static scoreToJsObject(score: Score): unknown { - const writer = new JsonWriter(); - ScoreSerializer.toJson(score, writer); - return writer.result; + return ScoreSerializer.toJson(score); } /** @@ -61,9 +57,9 @@ export class JsonConverter { * @param settings The settings to use during conversion. * @returns The converted score object. */ - public static jsObjectToScore(jsObject: any, settings?: Settings): Score { + public static jsObjectToScore(jsObject: unknown, settings?: Settings): Score { let score: Score = new Score(); - ScoreSerializer.fromJson(score, new JsonReader(jsObject)); + ScoreSerializer.fromJson(score, jsObject); score.finish(settings ?? new Settings()); return score; } @@ -73,10 +69,8 @@ export class JsonConverter { * @param settings The settings object to serialize * @returns A serialized settings object without ciruclar dependencies that can be used for further serializations. */ - public static settingsToJsObject(settings: Settings): unknown { - const writer = new JsonWriter(); - SettingsSerializer.toJson(settings, writer); - return writer.result; + public static settingsToJsObject(settings: Settings): Map | null { + return SettingsSerializer.toJson(settings); } /** @@ -84,9 +78,9 @@ export class JsonConverter { * @param jsObject The javascript object created via {@link Settings} * @returns The converted Settings object. */ - public static jsObjectToSettings(jsObject: any): Settings { + public static jsObjectToSettings(jsObject: unknown): Settings { let settings: Settings = new Settings(); - SettingsSerializer.fromJson(settings, new JsonReader(jsObject)); + SettingsSerializer.fromJson(settings, jsObject); return settings; } diff --git a/src/platform/javascript/AlphaTabWebWorker.ts b/src/platform/javascript/AlphaTabWebWorker.ts index 14e8f0493..cc7f4ad99 100644 --- a/src/platform/javascript/AlphaTabWebWorker.ts +++ b/src/platform/javascript/AlphaTabWebWorker.ts @@ -6,7 +6,6 @@ import { ScoreRenderer } from '@src/rendering/ScoreRenderer'; import { Settings } from '@src/Settings'; import { Logger } from '@src/Logger'; import { Environment } from '@src/Environment'; -import { JsonReader } from '@src/io/JsonReader'; import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** @@ -91,7 +90,7 @@ export class AlphaTabWebWorker { } private updateSettings(json: unknown): void { - SettingsSerializer.fromJson(this._renderer.settings, new JsonReader(json)); + SettingsSerializer.fromJson(this._renderer.settings, json); } private renderMultiple(score: Score, trackIndexes: number[]): void { diff --git a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts index 6ceb5da9d..17068de98 100644 --- a/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts +++ b/src/platform/javascript/AlphaTabWorkerScoreRenderer.ts @@ -59,9 +59,9 @@ export class AlphaTabWorkerScoreRenderer implements IScoreRenderer { } private serializeSettingsForWorker(settings: Settings): unknown { - const jsObject = JsonConverter.settingsToJsObject(settings); + const jsObject = JsonConverter.settingsToJsObject(settings)!; // cut out player settings, they are only needed on UI thread side - delete (jsObject as any).player; + jsObject.delete('player'); return jsObject; } diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index a62e983b5..e3a64dd0f 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -24,6 +24,7 @@ import { AlphaTabWorkerScoreRenderer } from '@src/platform/javascript/AlphaTabWo import { BrowserMouseEventArgs } from '@src/platform/javascript/BrowserMouseEventArgs'; import { Cursors } from '@src/platform/Cursors'; import { JsonConverter } from '@src/model/JsonConverter'; +import { SettingsSerializer } from '@src/generated/SettingsSerializer'; /** * @target web @@ -126,7 +127,7 @@ export class BrowserUiFacade implements IUiFacade { } let dataAttributes: Map = this.getDataAttributes(); - settings.fillFromDataAttributes(dataAttributes); + SettingsSerializer.fromJson(settings, dataAttributes); if (settings.notation.notationMode === NotationMode.SongBook) { settings.setSongBookModeSettings(); } diff --git a/test/model/Font.test.ts b/test/model/Font.test.ts index 99b859847..97f0529ac 100644 --- a/test/model/Font.test.ts +++ b/test/model/Font.test.ts @@ -1,10 +1,8 @@ -import { JsonReader } from "@src/io/JsonReader"; import { Font, FontStyle } from "@src/model/Font"; describe('FontTests', () => { function parseText(text: string, expected: Font) { - const reader = new JsonReader(text); - const font = Font.fromJson(reader); + const font = Font.fromJson(text); expect(font!.family).toEqual(expected.family); expect(font!.isBold).toEqual(expected.isBold); expect(font!.isItalic).toEqual(expected.isItalic); diff --git a/test/model/JsonConverter.test.ts b/test/model/JsonConverter.test.ts index 518e4ed39..1a466bc44 100644 --- a/test/model/JsonConverter.test.ts +++ b/test/model/JsonConverter.test.ts @@ -1,7 +1,6 @@ import { FingeringMode, LayoutMode, LogLevel, NotationMode, Settings, StaveProfile } from "@src/alphatab"; import { SettingsSerializer } from "@src/generated/SettingsSerializer"; import { ScoreLoader } from "@src/importer/ScoreLoader"; -import { JsonReader } from "@src/io/JsonReader"; import { Color } from "@src/model/Color"; import { Font, FontStyle } from "@src/model/Font"; import { JsonConverter } from "@src/model/JsonConverter"; @@ -235,11 +234,11 @@ describe('JsonConverterTest', () => { raw.set('enableLazyLoading', false); // string enum raw.set('logLevel', 'error'); - raw.set('displayLayoutMode', 1.0); + raw.set('displayLayoutMode', 1.0 as number); // nested const display = new Map(); - display.set('scale', 5.0); + display.set('scale', 5.0 as number); raw.set('display', display); // json_partial_names @@ -248,7 +247,7 @@ describe('JsonConverterTest', () => { // immutable raw.set('displayResourcesCopyrightFont', 'italic 18px Roboto'); - SettingsSerializer.fromJson(settings, new JsonReader(raw)); + SettingsSerializer.fromJson(settings, raw); expect(settings.core.enableLazyLoading).toEqual(false); expect(settings.core.logLevel).toEqual(LogLevel.Error); @@ -281,7 +280,7 @@ describe('JsonConverterTest', () => { displayResourcesCopyrightFont: 'italic 18px Roboto' }; - SettingsSerializer.fromJson(settings, new JsonReader(raw)); + SettingsSerializer.fromJson(settings, raw); expect(settings.core.enableLazyLoading).toEqual(false); expect(settings.core.logLevel).toEqual(LogLevel.Error); From c332c84534322937b34c3860f386a707cb5a58f7 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 27 Dec 2020 16:29:05 +0100 Subject: [PATCH 17/19] Optimize Build chain a bit --- src.compiler/TranspilerBase.ts | 15 ++++- src.compiler/csharp/CSharpAstTransformer.ts | 59 +++++++++----------- src.compiler/csharp/CSharpEmitter.ts | 6 +- src.compiler/csharp/CSharpTranspiler.ts | 5 +- src.compiler/typescript/AlphaTabGenerator.ts | 9 ++- 5 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src.compiler/TranspilerBase.ts b/src.compiler/TranspilerBase.ts index 25b4fd2b2..453b52709 100644 --- a/src.compiler/TranspilerBase.ts +++ b/src.compiler/TranspilerBase.ts @@ -18,7 +18,13 @@ function createDiagnosticReporter(pretty?: boolean): ts.DiagnosticReporter { }; } -export default function (emit: (program: ts.Program, diagnostics: ts.Diagnostic[]) => void, handleErrors: boolean = false) { +interface Emitter { + name: string, + emit(program: ts.Program, diagnostics: ts.Diagnostic[]): void; +} + +export default function (emitters: Emitter[], handleErrors: boolean = false) { + console.log('Parsing...'); const commandLine = ts.parseCommandLine(ts.sys.args); if (!ts.sys.fileExists(commandLine.options.project!)) { ts.sys.exit(ts.ExitStatus.InvalidProject_OutputsSkipped); @@ -57,7 +63,10 @@ export default function (emit: (program: ts.Program, diagnostics: ts.Diagnostic[ program.getTypeChecker(); - emit(program, allDiagnostics); + for(const emitter of emitters) { + console.log(`[${emitter.name}] Emitting...`); + emitter.emit(program, allDiagnostics); + } if (handleErrors) { let diagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); @@ -88,4 +97,6 @@ export default function (emit: (program: ts.Program, diagnostics: ts.Diagnostic[ ts.sys.exit(ts.ExitStatus.Success); } } + + console.log('Done'); } \ No newline at end of file diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts index 4108ab7cd..e4937d801 100644 --- a/src.compiler/csharp/CSharpAstTransformer.ts +++ b/src.compiler/csharp/CSharpAstTransformer.ts @@ -282,7 +282,7 @@ export default class CSharpAstTransformer { additionalNestedNonExportsDeclarations?: ts.Declaration[], globalStatements?: ts.Statement[] ): ts.Node { - if (this.shouldSkip(node)) { + if (this.shouldSkip(node, false)) { return node; } @@ -304,27 +304,20 @@ export default class CSharpAstTransformer { return node; } - private shouldSkip(node: ts.Node) { + private shouldSkip(node: ts.Node, checkComments: boolean) { + if (checkComments) { + const text = node.getSourceFile().text; + // check for /*@target web*/ marker + const commentText = text.substr(node.getStart() - node.getLeadingTriviaWidth(), node.getLeadingTriviaWidth()); + if(commentText.indexOf('/*@target web*/') >= 0) { + return true; + } + } const tags = ts.getJSDocTags(node).filter(t => t.tagName.text === 'target'); if (tags.length > 0) { return !tags.find(t => t.comment === 'csharp'); } - const text = node.getSourceFile().text; - const targets = ts.getLeadingCommentRanges(text, node.getStart() - node.getLeadingTriviaWidth()) - ?.map(r => { - let comment = text.substring(r.pos, r.end).trim(); - if (comment.indexOf('/*@target') >= 0) { - return comment.substring(9, comment.length - 2).trim(); - } else { - return ''; - } - }) - .filter(t => t.length > 0); - if (targets && targets.length > 0 && !targets.find(t => t === "csharp")) { - return true; - } - return false; } @@ -336,7 +329,7 @@ export default class CSharpAstTransformer { parent: this._csharpFile.namespace, members: [], tsNode: node, - skipEmit: this.shouldSkip(node), + skipEmit: this.shouldSkip(node, false), tsSymbol: this._context.getSymbolForDeclaration(node) }; @@ -356,7 +349,7 @@ export default class CSharpAstTransformer { tsNode: enumMember, nodeType: cs.SyntaxKind.EnumMember, name: enumMember.name.getText(), - skipEmit: this.shouldSkip(enumMember) + skipEmit: this.shouldSkip(enumMember, false) }; if (enumMember.initializer) { @@ -391,7 +384,7 @@ export default class CSharpAstTransformer { parent: this._csharpFile.namespace, members: [], tsNode: node, - skipEmit: this.shouldSkip(node), + skipEmit: this.shouldSkip(node, false), tsSymbol: this._context.getSymbolForDeclaration(node) }; @@ -542,7 +535,7 @@ export default class CSharpAstTransformer { returnType: this.createUnresolvedTypeNode(null, d.type ?? d, returnType), visibility: this.mapVisibility(d.modifiers), tsNode: d, - skipEmit: this.shouldSkip(d) + skipEmit: this.shouldSkip(d, true) }; csMethod.isAsync = !!d.modifiers && @@ -578,7 +571,7 @@ export default class CSharpAstTransformer { } as cs.PrimitiveTypeNode, visibility: cs.Visibility.Public, tsNode: d, - skipEmit: this.shouldSkip(d) + skipEmit: this.shouldSkip(d, true) }; if (csMethod.name.match(/^[^a-zA-Z].*/)) { @@ -711,7 +704,7 @@ export default class CSharpAstTransformer { isAbstract: !!node.modifiers && !!node.modifiers.find(m => m.kind === ts.SyntaxKind.AbstractKeyword), partial: !!ts.getJSDocTags(node).find(t => t.tagName.text === 'partial'), members: [], - skipEmit: this.shouldSkip(node), + skipEmit: this.shouldSkip(node, false), tsSymbol: this._context.getSymbolForDeclaration(node) }; @@ -884,7 +877,7 @@ export default class CSharpAstTransformer { type: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, type), visibility: cs.Visibility.None, tsNode: classElement, - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (classElement.name) { @@ -946,7 +939,7 @@ export default class CSharpAstTransformer { parent: parent, visibility: this.mapVisibility(classElement.modifiers), type: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, returnType), - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (newProperty.visibility === cs.Visibility.Public || newProperty.visibility === cs.Visibility.Protected) { @@ -1017,7 +1010,7 @@ export default class CSharpAstTransformer { parent: parent, visibility: this.mapVisibility(classElement.modifiers), type: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, returnType), - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (newProperty.visibility === cs.Visibility.Public || newProperty.visibility === cs.Visibility.Protected) { @@ -1079,7 +1072,7 @@ export default class CSharpAstTransformer { type: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, type), visibility: visibility, tsNode: classElement, - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (csProperty.visibility === cs.Visibility.Public || csProperty.visibility === cs.Visibility.Protected) { @@ -1179,7 +1172,7 @@ export default class CSharpAstTransformer { returnType: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, returnType), visibility: this.mapVisibility(classElement.modifiers), tsNode: classElement, - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (classElement.name) { @@ -1241,7 +1234,7 @@ export default class CSharpAstTransformer { } private visitStatement(parent: cs.Node, s: ts.Statement): cs.Statement | null { - if (this.shouldSkip(s)) { + if (this.shouldSkip(s, true)) { return null; } @@ -1665,10 +1658,10 @@ export default class CSharpAstTransformer { } private visitCaseClause(parent: cs.SwitchStatement, s: ts.CaseClause) { - if (this.shouldSkip(s)) { + if (this.shouldSkip(s, true)) { return null; } - + const caseClause = { nodeType: cs.SyntaxKind.CaseClause, parent: parent, @@ -1760,7 +1753,7 @@ export default class CSharpAstTransformer { returnType: this.createUnresolvedTypeNode(null, classElement.type ?? classElement, returnType), visibility: cs.Visibility.None, tsNode: classElement, - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; if (classElement.name) { @@ -1855,7 +1848,7 @@ export default class CSharpAstTransformer { isStatic: false, visibility: this.mapVisibility(classElement.modifiers), tsNode: classElement, - skipEmit: this.shouldSkip(classElement) + skipEmit: this.shouldSkip(classElement, false) }; classElement.parameters.forEach(p => this.visitMethodParameter(csConstructor, p)); diff --git a/src.compiler/csharp/CSharpEmitter.ts b/src.compiler/csharp/CSharpEmitter.ts index 71f9c1f03..20d5449d8 100644 --- a/src.compiler/csharp/CSharpEmitter.ts +++ b/src.compiler/csharp/CSharpEmitter.ts @@ -3,18 +3,22 @@ import CSharpAstTransformer from './CSharpAstTransformer'; import CSharpEmitterContext from './CSharpEmitterContext'; import CSharpAstPrinter from './CSharpAstPrinter'; -export default function emit(program: ts.Program, diagnostics:ts.Diagnostic[]) { +export default function emit(program: ts.Program, diagnostics: ts.Diagnostic[]) { const context = new CSharpEmitterContext(program); + console.log('[C#] Transforming to C# AST'); program.getRootFileNames().forEach(file => { const sourceFile = program.getSourceFile(file)!; const transformer = new CSharpAstTransformer(sourceFile, context); transformer.transform(); }); + + console.log('[C#] Resolving types'); context.resolveAllUnresolvedTypeNodes(); context.rewriteVisibilities(); if (!context.hasErrors) { + console.log('[C#] Writing Result'); context.csharpFiles.forEach(file => { const printer = new CSharpAstPrinter(file, context); printer.print(); diff --git a/src.compiler/csharp/CSharpTranspiler.ts b/src.compiler/csharp/CSharpTranspiler.ts index 9f890130e..949f6f3f8 100644 --- a/src.compiler/csharp/CSharpTranspiler.ts +++ b/src.compiler/csharp/CSharpTranspiler.ts @@ -1,4 +1,7 @@ import emit from './CSharpEmitter'; import transpiler from '../TranspilerBase' -transpiler(emit, true); \ No newline at end of file +transpiler([{ + name: 'C#', + emit: emit +}], true); \ No newline at end of file diff --git a/src.compiler/typescript/AlphaTabGenerator.ts b/src.compiler/typescript/AlphaTabGenerator.ts index 489cc1ae8..9afea6cff 100644 --- a/src.compiler/typescript/AlphaTabGenerator.ts +++ b/src.compiler/typescript/AlphaTabGenerator.ts @@ -3,7 +3,12 @@ import cloneEmit from './CloneEmitter'; import serializerEmit from './SerializerEmitter'; import transpiler from '../TranspilerBase' -transpiler(cloneEmit); -transpiler(serializerEmit); +transpiler([{ + name: 'Clone', + emit: cloneEmit +}, { + name: 'Serializer', + emit: serializerEmit +}]); ts.sys.exit(ts.ExitStatus.Success); \ No newline at end of file From fe46b3942b7a16ea87756c4aad660698320945a9 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 27 Dec 2020 18:04:56 +0100 Subject: [PATCH 18/19] Some optimizations --- src/generated/model/BarSerializer.ts | 4 -- src/generated/model/BeatSerializer.ts | 8 --- src/generated/model/MasterBarSerializer.ts | 4 -- src/generated/model/NoteCloner.ts | 2 - src/generated/model/NoteSerializer.ts | 12 ---- src/generated/model/StaffSerializer.ts | 4 -- src/generated/model/TrackSerializer.ts | 4 -- src/generated/model/VoiceSerializer.ts | 4 -- src/model/Bar.ts | 1 + src/model/Beat.ts | 4 ++ src/model/JsonConverter.ts | 70 ++++++++++++++++------ src/model/MasterBar.ts | 1 + src/model/Note.ts | 9 +++ src/model/Staff.ts | 1 + src/model/Track.ts | 1 + src/model/Voice.ts | 1 + 16 files changed, 69 insertions(+), 61 deletions(-) diff --git a/src/generated/model/BarSerializer.ts b/src/generated/model/BarSerializer.ts index da241461c..8bc18677e 100644 --- a/src/generated/model/BarSerializer.ts +++ b/src/generated/model/BarSerializer.ts @@ -23,7 +23,6 @@ export class BarSerializer { } const o = new Map(); o.set("id", obj.id); - o.set("index", obj.index); o.set("clef", (obj.clef as number)); o.set("clefOttava", (obj.clefOttava as number)); o.set("voices", obj.voices.map(i => VoiceSerializer.toJson(i))); @@ -35,9 +34,6 @@ export class BarSerializer { case "id": obj.id = (v as number); return true; - case "index": - obj.index = (v as number); - return true; case "clef": obj.clef = (JsonHelper.parseEnum(v, Clef)!); return true; diff --git a/src/generated/model/BeatSerializer.ts b/src/generated/model/BeatSerializer.ts index 4a3e94c5a..bd7a1037c 100644 --- a/src/generated/model/BeatSerializer.ts +++ b/src/generated/model/BeatSerializer.ts @@ -36,7 +36,6 @@ export class BeatSerializer { } const o = new Map(); o.set("id", obj.id); - o.set("index", obj.index); o.set("notes", obj.notes.map(i => NoteSerializer.toJson(i))); o.set("isEmpty", obj.isEmpty); o.set("whammyStyle", (obj.whammyStyle as number)); @@ -72,7 +71,6 @@ export class BeatSerializer { o.set("dynamics", (obj.dynamics as number)); o.set("invertBeamDirection", obj.invertBeamDirection); o.set("preferredBeamDirection", (obj.preferredBeamDirection as number | null)); - o.set("isEffectSlurOrigin", obj.isEffectSlurOrigin); o.set("beamingMode", (obj.beamingMode as number)); return o; } @@ -81,9 +79,6 @@ export class BeatSerializer { case "id": obj.id = (v as number); return true; - case "index": - obj.index = (v as number); - return true; case "notes": obj.notes = []; for (const o of (v as (Map | null)[])) { @@ -204,9 +199,6 @@ export class BeatSerializer { case "preferredbeamdirection": obj.preferredBeamDirection = JsonHelper.parseEnum(v, BeamDirection); return true; - case "iseffectslurorigin": - obj.isEffectSlurOrigin = (v as boolean); - return true; case "beamingmode": obj.beamingMode = (JsonHelper.parseEnum(v, BeatBeamingMode)!); return true; diff --git a/src/generated/model/MasterBarSerializer.ts b/src/generated/model/MasterBarSerializer.ts index aaf90e63d..b0e8c8c3e 100644 --- a/src/generated/model/MasterBarSerializer.ts +++ b/src/generated/model/MasterBarSerializer.ts @@ -27,7 +27,6 @@ export class MasterBarSerializer { } const o = new Map(); o.set("alternateEndings", obj.alternateEndings); - o.set("index", obj.index); o.set("keySignature", (obj.keySignature as number)); o.set("keySignatureType", (obj.keySignatureType as number)); o.set("isDoubleBar", obj.isDoubleBar); @@ -53,9 +52,6 @@ export class MasterBarSerializer { case "alternateendings": obj.alternateEndings = (v as number); return true; - case "index": - obj.index = (v as number); - return true; case "keysignature": obj.keySignature = (JsonHelper.parseEnum(v, KeySignature)!); return true; diff --git a/src/generated/model/NoteCloner.ts b/src/generated/model/NoteCloner.ts index ed4f90a0d..8cc7eb248 100644 --- a/src/generated/model/NoteCloner.ts +++ b/src/generated/model/NoteCloner.ts @@ -51,8 +51,6 @@ export class NoteCloner { clone.durationPercent = original.durationPercent; clone.accidentalMode = original.accidentalMode; clone.dynamics = original.dynamics; - clone.isEffectSlurOrigin = original.isEffectSlurOrigin; - clone.hasEffectSlur = original.hasEffectSlur; return clone; } } diff --git a/src/generated/model/NoteSerializer.ts b/src/generated/model/NoteSerializer.ts index 798988bd5..938483021 100644 --- a/src/generated/model/NoteSerializer.ts +++ b/src/generated/model/NoteSerializer.ts @@ -31,7 +31,6 @@ export class NoteSerializer { } const o = new Map(); o.set("id", obj.id); - o.set("index", obj.index); o.set("accentuated", (obj.accentuated as number)); o.set("bendType", (obj.bendType as number)); o.set("bendStyle", (obj.bendStyle as number)); @@ -71,8 +70,6 @@ export class NoteSerializer { o.set("durationPercent", obj.durationPercent); o.set("accidentalMode", (obj.accidentalMode as number)); o.set("dynamics", (obj.dynamics as number)); - o.set("isEffectSlurOrigin", obj.isEffectSlurOrigin); - o.set("hasEffectSlur", obj.hasEffectSlur); return o; } public static setProperty(obj: Note, property: string, v: unknown): boolean { @@ -80,9 +77,6 @@ export class NoteSerializer { case "id": obj.id = (v as number); return true; - case "index": - obj.index = (v as number); - return true; case "accentuated": obj.accentuated = (JsonHelper.parseEnum(v, AccentuationType)!); return true; @@ -205,12 +199,6 @@ export class NoteSerializer { case "dynamics": obj.dynamics = (JsonHelper.parseEnum(v, DynamicValue)!); return true; - case "iseffectslurorigin": - obj.isEffectSlurOrigin = (v as boolean); - return true; - case "haseffectslur": - obj.hasEffectSlur = (v as boolean); - return true; } return false; } diff --git a/src/generated/model/StaffSerializer.ts b/src/generated/model/StaffSerializer.ts index 64db41406..ed35f0514 100644 --- a/src/generated/model/StaffSerializer.ts +++ b/src/generated/model/StaffSerializer.ts @@ -21,7 +21,6 @@ export class StaffSerializer { return null; } const o = new Map(); - o.set("index", obj.index); o.set("bars", obj.bars.map(i => BarSerializer.toJson(i))); { const m = new Map(); @@ -41,9 +40,6 @@ export class StaffSerializer { } public static setProperty(obj: Staff, property: string, v: unknown): boolean { switch (property) { - case "index": - obj.index = (v as number); - return true; case "bars": obj.bars = []; for (const o of (v as (Map | null)[])) { diff --git a/src/generated/model/TrackSerializer.ts b/src/generated/model/TrackSerializer.ts index fb0efcd82..717df3306 100644 --- a/src/generated/model/TrackSerializer.ts +++ b/src/generated/model/TrackSerializer.ts @@ -23,7 +23,6 @@ export class TrackSerializer { return null; } const o = new Map(); - o.set("index", obj.index); o.set("staves", obj.staves.map(i => StaffSerializer.toJson(i))); o.set("playbackInfo", PlaybackInformationSerializer.toJson(obj.playbackInfo)); o.set("color", Color.toJson(obj.color)); @@ -34,9 +33,6 @@ export class TrackSerializer { } public static setProperty(obj: Track, property: string, v: unknown): boolean { switch (property) { - case "index": - obj.index = (v as number); - return true; case "staves": obj.staves = []; for (const o of (v as (Map | null)[])) { diff --git a/src/generated/model/VoiceSerializer.ts b/src/generated/model/VoiceSerializer.ts index cf29dadbe..cb0eab375 100644 --- a/src/generated/model/VoiceSerializer.ts +++ b/src/generated/model/VoiceSerializer.ts @@ -19,16 +19,12 @@ export class VoiceSerializer { return null; } const o = new Map(); - o.set("index", obj.index); o.set("beats", obj.beats.map(i => BeatSerializer.toJson(i))); o.set("isEmpty", obj.isEmpty); return o; } public static setProperty(obj: Voice, property: string, v: unknown): boolean { switch (property) { - case "index": - obj.index = (v as number); - return true; case "beats": obj.beats = []; for (const o of (v as (Map | null)[])) { diff --git a/src/model/Bar.ts b/src/model/Bar.ts index f72095e4b..92d01cd07 100644 --- a/src/model/Bar.ts +++ b/src/model/Bar.ts @@ -20,6 +20,7 @@ export class Bar { /** * Gets or sets the zero-based index of this bar within the staff. + * @json_ignore */ public index: number = 0; diff --git a/src/model/Beat.ts b/src/model/Beat.ts index 407095c6f..c814d7070 100644 --- a/src/model/Beat.ts +++ b/src/model/Beat.ts @@ -58,6 +58,7 @@ export class Beat { /** * Gets or sets the zero-based index of this beat within the voice. + * @json_ignore */ public index: number = 0; @@ -388,6 +389,9 @@ export class Beat { */ public preferredBeamDirection: BeamDirection | null = null; + /** + * @json_ignore + */ public isEffectSlurOrigin: boolean = false; public get isEffectSlurDestination(): boolean { diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index c84967304..67307d0f8 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -14,41 +14,51 @@ import { SettingsSerializer } from '@src/generated/SettingsSerializer'; * JSON serialization. */ export class JsonConverter { + private static jsonReplacer(_: any, v: any) { + if (v instanceof Map) { + if ('fromEntries' in Object) { + return (Object as any).fromEntries(v); + } else { + const o: any = {}; + v.forEach((v, k) => o[k] = v); + return o; + } + } + else if (ArrayBuffer.isView(v)) { + return Array.apply([], [v]); + } + return v; + } + /** * Converts the given score into a JSON encoded string. * @param score The score to serialize. - * @returns A JSON encoded string that can be used togehter with for conversion. + * @returns A JSON encoded string. * @target web */ public static scoreToJson(score: Score): string { let obj: unknown = JsonConverter.scoreToJsObject(score); - return JSON.stringify(obj, (_, v) => { - // patch arraybuffer to serialize as array - if (ArrayBuffer.isView(v)) { - return Array.apply([], [v]); - } - return v; - }); - } - - /** - * Converts the score into a JavaScript object without circular dependencies. - * @param score The score object to serialize - * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. - */ - public static scoreToJsObject(score: Score): unknown { - return ScoreSerializer.toJson(score); + return JSON.stringify(obj, JsonConverter.jsonReplacer); } /** * Converts the given JSON string back to a {@link Score} object. - * @param json The JSON string that was created via {@link Score} + * @param json The JSON string * @param settings The settings to use during conversion. * @returns The converted score object. * @target web */ public static jsonToScore(json: string, settings?: Settings): Score { - return JsonConverter.jsObjectToScore(json, settings); + return JsonConverter.jsObjectToScore(JSON.parse(json), settings); + } + + /** + * Converts the score into a JavaScript object without circular dependencies. + * @param score The score object to serialize + * @returns A serialized score object without ciruclar dependencies that can be used for further serializations. + */ + public static scoreToJsObject(score: Score): unknown { + return ScoreSerializer.toJson(score); } /** @@ -64,6 +74,28 @@ export class JsonConverter { return score; } + + /** + * Converts the given settings into a JSON encoded string. + * @param settings The settings to serialize. + * @returns A JSON encoded string. + * @target web + */ + public static settingsToJson(settings: Settings): string { + let obj: unknown = JsonConverter.settingsToJsObject(settings); + return JSON.stringify(obj, JsonConverter.jsonReplacer); + } + + /** + * Converts the given JSON string back to a {@link Score} object. + * @param json The JSON string + * @returns The converted settings object. + * @target web + */ + public static jsonToSettings(json: string): Settings { + return JsonConverter.jsObjectToSettings(JSON.parse(json)); + } + /** * Converts the settings object into a JavaScript object for transmission between components or saving purposes. * @param settings The settings object to serialize diff --git a/src/model/MasterBar.ts b/src/model/MasterBar.ts index 0fd037e12..6f01444b6 100644 --- a/src/model/MasterBar.ts +++ b/src/model/MasterBar.ts @@ -36,6 +36,7 @@ export class MasterBar { /** * Gets the zero based index of the masterbar. + * @json_ignore */ public index: number = 0; diff --git a/src/model/Note.ts b/src/model/Note.ts index 5121091cf..78f900f98 100644 --- a/src/model/Note.ts +++ b/src/model/Note.ts @@ -38,6 +38,7 @@ export class Note { /** * Gets or sets the zero-based index of this note within the beat. + * @json_ignore */ public index: number = 0; @@ -485,8 +486,16 @@ export class Note { */ public dynamics: DynamicValue = DynamicValue.F; + /** + * @clone_ignore + * @json_ignore + */ public isEffectSlurOrigin: boolean = false; + /** + * @clone_ignore + * @json_ignore + */ public hasEffectSlur: boolean = false; public get isEffectSlurDestination(): boolean { diff --git a/src/model/Staff.ts b/src/model/Staff.ts index d38b205ac..ea301b9ea 100644 --- a/src/model/Staff.ts +++ b/src/model/Staff.ts @@ -11,6 +11,7 @@ import { Settings } from '@src/Settings'; export class Staff { /** * Gets or sets the zero-based index of this staff within the track. + * @json_ignore */ public index: number = 0; diff --git a/src/model/Track.ts b/src/model/Track.ts index f29c368c6..7c6327d3b 100644 --- a/src/model/Track.ts +++ b/src/model/Track.ts @@ -16,6 +16,7 @@ export class Track { private static readonly ShortNameMaxLength: number = 10; /** * Gets or sets the zero-based index of this track. + * @json_ignore */ public index: number = 0; diff --git a/src/model/Voice.ts b/src/model/Voice.ts index 67c8e8fba..5f03671a0 100644 --- a/src/model/Voice.ts +++ b/src/model/Voice.ts @@ -15,6 +15,7 @@ export class Voice { /** * Gets or sets the zero-based index of this voice within the bar. + * @json_ignore */ public index: number = 0; From 3eb2409ed9f024b22f8b8d0520581166b6142323 Mon Sep 17 00:00:00 2001 From: Danielku15 Date: Sun, 27 Dec 2020 18:21:01 +0100 Subject: [PATCH 19/19] Fix c# build --- src/model/JsonConverter.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/model/JsonConverter.ts b/src/model/JsonConverter.ts index 67307d0f8..86cc07567 100644 --- a/src/model/JsonConverter.ts +++ b/src/model/JsonConverter.ts @@ -14,6 +14,9 @@ import { SettingsSerializer } from '@src/generated/SettingsSerializer'; * JSON serialization. */ export class JsonConverter { + /** + * @target web + */ private static jsonReplacer(_: any, v: any) { if (v instanceof Map) { if ('fromEntries' in Object) {