From 77add4162bbe4ea670d2b8f1fca3097d54ca193d Mon Sep 17 00:00:00 2001 From: Pankaj Khandelwal Date: Mon, 21 Sep 2020 10:40:48 +0200 Subject: [PATCH] Fixes microsoft/monaco-editor#1999: Use parent stack to keep track of the current parent and previous parents for any particular key or value part --- src/tokenization.ts | 97 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/src/tokenization.ts b/src/tokenization.ts index ab8e3e0b..758e0ca9 100644 --- a/src/tokenization.ts +++ b/src/tokenization.ts @@ -10,7 +10,7 @@ export function createTokenizationSupport( supportComments: boolean ): languages.TokensProvider { return { - getInitialState: () => new JSONState(null, null), + getInitialState: () => new JSONState(null, null, false, []), tokenize: (line, state, offsetDelta?, stopAtOffset?) => tokenize( supportComments, @@ -34,18 +34,60 @@ export const TOKEN_PROPERTY_NAME = 'string.key.json'; export const TOKEN_COMMENT_BLOCK = 'comment.block.json'; export const TOKEN_COMMENT_LINE = 'comment.line.json'; +enum JSONParent { + Object = 0, + Array = 1 +} + class JSONState implements languages.IState { private _state: languages.IState; public scanError: json.ScanError; + public lastWasColon: boolean; + public parents: JSONParent[]; - constructor(state: languages.IState, scanError: json.ScanError) { + constructor( + state: languages.IState, + scanError: json.ScanError, + lastWasColon: boolean, + parents: JSONParent[] + ) { this._state = state; this.scanError = scanError; + this.lastWasColon = lastWasColon; + this.parents = parents; + } + + private static areArraysEqual(first: JSONParent[], second: JSONParent[]) { + if (first === second) { + return true; + } + + if (first == null || second === null) { + return false; + } + + if (first.length !== second.length) { + return false; + } + + let index = -1; + while (++index < first.length) { + if (first[index] !== second[index]) { + return false; + } + } + + return true; } public clone(): JSONState { - return new JSONState(this._state, this.scanError); + return new JSONState( + this._state, + this.scanError, + this.lastWasColon, + this.parents + ); } public equals(other: languages.IState): boolean { @@ -55,7 +97,11 @@ class JSONState implements languages.IState { if (!other || !(other instanceof JSONState)) { return false; } - return this.scanError === (other).scanError; + return ( + this.scanError === (other).scanError && + this.lastWasColon === (other).lastWasColon && + JSONState.areArraysEqual(this.parents, (other).parents) + ); } public getStateData(): languages.IState { @@ -89,7 +135,9 @@ function tokenize( break; } - const scanner = json.createScanner(line); + let scanner = json.createScanner(line), + lastWasColon = state.lastWasColon, + parents = Array.from(state.parents); const ret: languages.ILineTokens = { tokens: [], @@ -123,46 +171,54 @@ function tokenize( // brackets and type switch (kind) { case json.SyntaxKind.OpenBraceToken: + parents.push(JSONParent.Object); type = TOKEN_DELIM_OBJECT; + lastWasColon = false; break; case json.SyntaxKind.CloseBraceToken: + parents.pop(); type = TOKEN_DELIM_OBJECT; + lastWasColon = false; break; case json.SyntaxKind.OpenBracketToken: + parents.push(JSONParent.Array); type = TOKEN_DELIM_ARRAY; + lastWasColon = false; break; case json.SyntaxKind.CloseBracketToken: + parents.pop(); type = TOKEN_DELIM_ARRAY; + lastWasColon = false; break; case json.SyntaxKind.ColonToken: - for (let i = ret.tokens.length - 1; i >= 0; i--) { - const token = ret.tokens[i]; - if (token.scopes === '' || token.scopes === TOKEN_COMMENT_BLOCK) { - continue; - } - if (token.scopes === TOKEN_VALUE_STRING) { - // !change previous token to property name! - token.scopes = TOKEN_PROPERTY_NAME; - } - break; - } type = TOKEN_DELIM_COLON; + lastWasColon = true; break; case json.SyntaxKind.CommaToken: type = TOKEN_DELIM_COMMA; + lastWasColon = false; break; case json.SyntaxKind.TrueKeyword: case json.SyntaxKind.FalseKeyword: type = TOKEN_VALUE_BOOLEAN; + lastWasColon = false; break; case json.SyntaxKind.NullKeyword: type = TOKEN_VALUE_NULL; + lastWasColon = false; break; case json.SyntaxKind.StringLiteral: - type = TOKEN_VALUE_STRING; + let currentParent = parents.length + ? parents[parents.length - 1] + : JSONParent.Object; + let inArray = currentParent === JSONParent.Array; + type = + lastWasColon || inArray ? TOKEN_VALUE_STRING : TOKEN_PROPERTY_NAME; + lastWasColon = false; break; case json.SyntaxKind.NumericLiteral: type = TOKEN_VALUE_NUMBER; + lastWasColon = false; break; } @@ -178,7 +234,12 @@ function tokenize( } } - ret.endState = new JSONState(state.getStateData(), scanner.getTokenError()); + ret.endState = new JSONState( + state.getStateData(), + scanner.getTokenError(), + lastWasColon, + parents + ); ret.tokens.push({ startIndex: offset, scopes: type