diff --git a/openrewrite/src/javascript/parser.ts b/openrewrite/src/javascript/parser.ts index 1320e614..0989b166 100644 --- a/openrewrite/src/javascript/parser.ts +++ b/openrewrite/src/javascript/parser.ts @@ -262,11 +262,12 @@ export class JavaScriptParserVisitor { private mapModifiers(node: ts.VariableDeclarationList | ts.VariableStatement | ts.ClassDeclaration | ts.PropertyDeclaration | ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration | ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration - | ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration | ts.ExportDeclaration | ts.ExportAssignment) { + | ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration | ts.ExportDeclaration | ts.ExportAssignment | ts.FunctionExpression) { if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node) || ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node) - || ts.isIndexSignatureDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isExportDeclaration(node) || ts.isFunctionDeclaration(node)) { + || ts.isIndexSignatureDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isExportDeclaration(node) + || ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) { return node.modifiers ? node.modifiers?.filter(ts.isModifier).map(this.mapModifier) : []; } else if (ts.isExportAssignment(node)) { @@ -1210,8 +1211,9 @@ export class JavaScriptParserVisitor { this.prefix(node), Markers.EMPTY, this.rightPadded(false, Space.EMPTY), + this.mapTypeParametersAsObject(node), new JContainer( - this.prefix(node), + this.prefix(node.getChildAt(node.getChildren().findIndex(n => n.pos === node.parameters.pos) - 1)), node.parameters.map(p => this.rightPadded(this.visit(p), this.suffix(p))), Markers.EMPTY), this.prefix(this.findChildNode(node, ts.SyntaxKind.EqualsGreaterThanToken)!), @@ -1225,8 +1227,9 @@ export class JavaScriptParserVisitor { this.prefix(node), Markers.EMPTY, this.rightPadded(true, this.suffix(this.findChildNode(node, ts.SyntaxKind.NewKeyword)!)), + this.mapTypeParametersAsObject(node), new JContainer( - this.prefix(node), + this.prefix(node.getChildAt(node.getChildren().findIndex(n => n.pos === node.parameters.pos) - 1)), node.parameters.map(p => this.rightPadded(this.visit(p), this.suffix(p))), Markers.EMPTY), this.prefix(this.findChildNode(node, ts.SyntaxKind.EqualsGreaterThanToken)!), @@ -1826,7 +1829,7 @@ export class JavaScriptParserVisitor { randomId(), this.prefix(node), Markers.EMPTY, - [], + this.mapModifiers(node), this.leftPadded(this.prefix(this.findChildNode(node, ts.SyntaxKind.FunctionKeyword)!), !!node.asteriskToken), this.leftPadded(node.asteriskToken ? this.prefix(node.asteriskToken) : Space.EMPTY, node.name ? this.visit(node.name) : new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, [], "", null, null)), this.mapTypeParametersAsObject(node), @@ -3525,20 +3528,17 @@ export class JavaScriptParserVisitor { } private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration - | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration) : J.TypeParameters | null { - if (!node.typeParameters) return null; - - let ts_prefix: Space; - if (ts.isConstructSignatureDeclaration(node)) { - ts_prefix = this.suffix(this.findChildNode(node, ts.SyntaxKind.NewKeyword)!); - } else if (ts.isFunctionExpression(node)) { - ts_prefix = this.suffix(this.findChildNode(node, ts.SyntaxKind.FunctionKeyword)!); - } else if (ts.isTypeAliasDeclaration(node)) { - ts_prefix = this.suffix(node.name); - } else { - ts_prefix = node.questionToken ? this.suffix(node.questionToken) : node.name ? this.suffix(node.name) : Space.EMPTY; - } - return new J.TypeParameters(randomId(), ts_prefix, Markers.EMPTY, [], node.typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp)))); + | ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration | ts.FunctionTypeNode | ts.ConstructorTypeNode) : J.TypeParameters | null { + const typeParameters = node.typeParameters; + if (!typeParameters) return null; + + return new J.TypeParameters( + randomId(), + this.prefix(node.getChildAt(node.getChildren().findIndex(n => n.pos === typeParameters[0].pos) - 1)), + Markers.EMPTY, + [], + typeParameters.map(tp => this.rightPadded(this.visit(tp), this.suffix(tp))) + ); } private mapTypeParametersList(typeParamsNodeArray: ts.NodeArray) : JRightPadded[] { diff --git a/openrewrite/src/javascript/remote/receiver.ts b/openrewrite/src/javascript/remote/receiver.ts index d31b3704..e91eccfc 100644 --- a/openrewrite/src/javascript/remote/receiver.ts +++ b/openrewrite/src/javascript/remote/receiver.ts @@ -137,6 +137,7 @@ class Visitor extends JavaScriptVisitor { functionType = functionType.withPrefix(ctx.receiveNode(functionType.prefix, receiveSpace)!); functionType = functionType.withMarkers(ctx.receiveNode(functionType.markers, ctx.receiveMarkers)!); functionType = functionType.padding.withConstructorType(ctx.receiveNode(functionType.padding.constructorType, rightPaddedValueReceiver(ValueType.Primitive))!); + functionType = functionType.withTypeParameters(ctx.receiveNode(functionType.typeParameters, ctx.receiveTree)); functionType = functionType.padding.withParameters(ctx.receiveNode(functionType.padding.parameters, receiveContainer)!); functionType = functionType.withArrow(ctx.receiveNode(functionType.arrow, receiveSpace)!); functionType = functionType.withReturnType(ctx.receiveNode(functionType.returnType, ctx.receiveTree)!); @@ -1382,6 +1383,7 @@ class Factory implements ReceiverFactory { ctx.receiveNode(null, receiveSpace)!, ctx.receiveNode(null, ctx.receiveMarkers)!, ctx.receiveNode>(null, rightPaddedValueReceiver(ValueType.Primitive))!, + ctx.receiveNode(null, ctx.receiveTree), ctx.receiveNode>(null, receiveContainer)!, ctx.receiveNode(null, receiveSpace)!, ctx.receiveNode(null, ctx.receiveTree)!, diff --git a/openrewrite/src/javascript/remote/sender.ts b/openrewrite/src/javascript/remote/sender.ts index 90ae8ee7..fdb0d684 100644 --- a/openrewrite/src/javascript/remote/sender.ts +++ b/openrewrite/src/javascript/remote/sender.ts @@ -132,6 +132,7 @@ class Visitor extends JavaScriptVisitor { ctx.sendNode(functionType, v => v.prefix, Visitor.sendSpace); ctx.sendNode(functionType, v => v.markers, ctx.sendMarkers); ctx.sendNode(functionType, v => v.padding.constructorType, Visitor.sendRightPadded(ValueType.Primitive)); + ctx.sendNode(functionType, v => v.typeParameters, ctx.sendTree); ctx.sendNode(functionType, v => v.padding.parameters, Visitor.sendContainer(ValueType.Tree)); ctx.sendNode(functionType, v => v.arrow, Visitor.sendSpace); ctx.sendNode(functionType, v => v.returnType, ctx.sendTree); diff --git a/openrewrite/src/javascript/tree/tree.ts b/openrewrite/src/javascript/tree/tree.ts index 2fdad8d6..b48e4690 100644 --- a/openrewrite/src/javascript/tree/tree.ts +++ b/openrewrite/src/javascript/tree/tree.ts @@ -894,12 +894,13 @@ export class ExpressionWithTypeArguments extends JSMixin(Object) implements Type @LstType("org.openrewrite.javascript.tree.JS$FunctionType") export class FunctionType extends JSMixin(Object) implements Expression, TypeTree { - public constructor(id: UUID, prefix: Space, markers: Markers, constructorType: JRightPadded, parameters: JContainer, arrow: Space, returnType: Expression, _type: JavaType | null) { + public constructor(id: UUID, prefix: Space, markers: Markers, constructorType: JRightPadded, typeParameters: Java.TypeParameters | null, parameters: JContainer, arrow: Space, returnType: Expression, _type: JavaType | null) { super(); this._id = id; this._prefix = prefix; this._markers = markers; this._constructorType = constructorType; + this._typeParameters = typeParameters; this._parameters = parameters; this._arrow = arrow; this._returnType = returnType; @@ -913,7 +914,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withId(id: UUID): FunctionType { - return id === this._id ? this : new FunctionType(id, this._prefix, this._markers, this._constructorType, this._parameters, this._arrow, this._returnType, this._type); + return id === this._id ? this : new FunctionType(id, this._prefix, this._markers, this._constructorType, this._typeParameters, this._parameters, this._arrow, this._returnType, this._type); } private readonly _prefix: Space; @@ -923,7 +924,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withPrefix(prefix: Space): FunctionType { - return prefix === this._prefix ? this : new FunctionType(this._id, prefix, this._markers, this._constructorType, this._parameters, this._arrow, this._returnType, this._type); + return prefix === this._prefix ? this : new FunctionType(this._id, prefix, this._markers, this._constructorType, this._typeParameters, this._parameters, this._arrow, this._returnType, this._type); } private readonly _markers: Markers; @@ -933,7 +934,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withMarkers(markers: Markers): FunctionType { - return markers === this._markers ? this : new FunctionType(this._id, this._prefix, markers, this._constructorType, this._parameters, this._arrow, this._returnType, this._type); + return markers === this._markers ? this : new FunctionType(this._id, this._prefix, markers, this._constructorType, this._typeParameters, this._parameters, this._arrow, this._returnType, this._type); } private readonly _constructorType: JRightPadded; @@ -946,6 +947,16 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre return this.padding.withConstructorType(this._constructorType.withElement(constructorType)); } + private readonly _typeParameters: Java.TypeParameters | null; + + public get typeParameters(): Java.TypeParameters | null { + return this._typeParameters; + } + + public withTypeParameters(typeParameters: Java.TypeParameters | null): FunctionType { + return typeParameters === this._typeParameters ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, typeParameters, this._parameters, this._arrow, this._returnType, this._type); + } + private readonly _parameters: JContainer; public get parameters(): Statement[] { @@ -963,7 +974,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withArrow(arrow: Space): FunctionType { - return arrow === this._arrow ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._parameters, arrow, this._returnType, this._type); + return arrow === this._arrow ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._typeParameters, this._parameters, arrow, this._returnType, this._type); } private readonly _returnType: Expression; @@ -973,7 +984,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withReturnType(returnType: Expression): FunctionType { - return returnType === this._returnType ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._parameters, this._arrow, returnType, this._type); + return returnType === this._returnType ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._typeParameters, this._parameters, this._arrow, returnType, this._type); } private readonly _type: JavaType | null; @@ -983,7 +994,7 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre } public withType(_type: JavaType | null): FunctionType { - return _type === this._type ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._parameters, this._arrow, this._returnType, _type); + return _type === this._type ? this : new FunctionType(this._id, this._prefix, this._markers, this._constructorType, this._typeParameters, this._parameters, this._arrow, this._returnType, _type); } public acceptJavaScript

(v: JavaScriptVisitor

, p: P): J | null { @@ -997,13 +1008,13 @@ export class FunctionType extends JSMixin(Object) implements Expression, TypeTre return t._constructorType; } public withConstructorType(constructorType: JRightPadded): FunctionType { - return t._constructorType === constructorType ? t : new FunctionType(t._id, t._prefix, t._markers, constructorType, t._parameters, t._arrow, t._returnType, t._type); + return t._constructorType === constructorType ? t : new FunctionType(t._id, t._prefix, t._markers, constructorType, t._typeParameters, t._parameters, t._arrow, t._returnType, t._type); } public get parameters(): JContainer { return t._parameters; } public withParameters(parameters: JContainer): FunctionType { - return t._parameters === parameters ? t : new FunctionType(t._id, t._prefix, t._markers, t._constructorType, parameters, t._arrow, t._returnType, t._type); + return t._parameters === parameters ? t : new FunctionType(t._id, t._prefix, t._markers, t._constructorType, t._typeParameters, parameters, t._arrow, t._returnType, t._type); } } } diff --git a/openrewrite/src/javascript/visitor.ts b/openrewrite/src/javascript/visitor.ts index 2bacb66f..2f060bc1 100644 --- a/openrewrite/src/javascript/visitor.ts +++ b/openrewrite/src/javascript/visitor.ts @@ -165,6 +165,7 @@ export class JavaScriptVisitor

extends JavaVisitor

{ functionType = tempExpression as FunctionType; functionType = functionType.withMarkers(this.visitMarkers(functionType.markers, p)); functionType = functionType.padding.withConstructorType(this.visitJsRightPadded(functionType.padding.constructorType, JsRightPadded.Location.FUNCTION_TYPE_CONSTRUCTOR_TYPE, p)!); + functionType = functionType.withTypeParameters(this.visitAndCast(functionType.typeParameters, p)); functionType = functionType.padding.withParameters(this.visitJsContainer(functionType.padding.parameters, JsContainer.Location.FUNCTION_TYPE_PARAMETERS, p)!); functionType = functionType.withArrow(this.visitJsSpace(functionType.arrow, JsSpace.Location.FUNCTION_TYPE_ARROW, p)!); functionType = functionType.withReturnType(this.visitAndCast(functionType.returnType, p)!); diff --git a/openrewrite/test/javascript/e2e/highlight_js_files.test.ts b/openrewrite/test/javascript/e2e/highlight_js_files.test.ts index 4f773c7f..0d18d0fe 100644 --- a/openrewrite/test/javascript/e2e/highlight_js_files.test.ts +++ b/openrewrite/test/javascript/e2e/highlight_js_files.test.ts @@ -191,4 +191,367 @@ describe('highlight.js files tests', () => { ); }); + test('test/browser/worker.js', () => { + rewriteRun( + //language=typescript + typeScript(` + 'use strict'; + + const Worker = require('tiny-worker'); + + const { defaultCase, findLibrary } = require('./test_case') + + describe('web worker', function() { + before(async function() { + this.hljsPath = await findLibrary(); + this.worker = new Worker(function() { + self.onmessage = function(event) { + if (event.data.action === 'importScript') { + importScripts(event.data.script); + postMessage(1); + } else { + var result = hljs.highlight(event.data, { language: 'javascript' }); + postMessage(result.value); + } + }; + }); + + const done = new Promise(resolve => this.worker.onmessage = resolve); + this.worker.postMessage({ + action: 'importScript', + script: this.hljsPath + }); + return done; + }); + + it('should highlight text', function(done) { + this.worker.onmessage = event => { + const actual = event.data; + + // the " will be encoded since it's not being + // filtered by the browsers innerHTML implementation + const expect = '' + + 'var say = ' + + '"Hello";'; + actual.should.equal(expect); + + done(); + }; + + this.worker.postMessage(defaultCase.code); + }); + + after(function() { + this.worker.terminate(); + }); + }); + `) + ); + }); + + test('types/index.d.ts', () => { + rewriteRun( + //language=typescript + typeScript(` + /* eslint-disable no-unused-vars */ + /* eslint-disable no-use-before-define */ + // For TS consumers who use Node and don't have dom in their tsconfig lib, import the necessary types here. + /// + + declare module 'highlight.js/private' { + import {CompiledMode, Mode, Language} from "highlight.js"; + + type MatchType = "begin" | "end" | "illegal" + type EnhancedMatch = RegExpMatchArray & { rule: CompiledMode, type: MatchType } + type AnnotatedError = Error & { mode?: Mode | Language, languageName?: string, badRule?: Mode } + + type KeywordData = [string, number]; + type KeywordDict = Record + } + declare module 'highlight.js' { + + import {KeywordDict} from "highlight.js/private"; + + export type HLJSApi = PublicApi & ModesAPI + + export interface VuePlugin { + install: (vue: any) => void + } + + // perhaps make this an interface? + type RegexEitherOptions = { + capture?: boolean + } + + interface PublicApi { + highlight(code: string, options: HighlightOptions): HighlightResult + + /** @deprecated use \`higlight(code, {lang: ..., ignoreIllegals: ...})\` */ + highlight(languageName: string, code: string, ignoreIllegals?: boolean): HighlightResult + + highlightAuto: (code: string, languageSubset?: string[]) => AutoHighlightResult + highlightBlock: (element: HTMLElement) => void + highlightElement: (element: HTMLElement) => void + configure: (options: Partial) => void + initHighlighting: () => void + initHighlightingOnLoad: () => void + highlightAll: () => void + registerLanguage: (languageName: string, language: LanguageFn) => void + unregisterLanguage: (languageName: string) => void + listLanguages: () => string[] + registerAliases: (aliasList: string | string[], {languageName}: { languageName: string }) => void + getLanguage: (languageName: string) => Language | undefined + autoDetection: (languageName: string) => boolean + inherit: (original: T, ...args: Record[]) => T + addPlugin: (plugin: HLJSPlugin) => void + removePlugin: (plugin: HLJSPlugin) => void + debugMode: () => void + safeMode: () => void + versionString: string + vuePlugin: () => VuePlugin + regex: { + concat: (...args: (RegExp | string)[]) => string, + lookahead: (re: RegExp | string) => string, + either: (...args: (RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]) => string, + optional: (re: RegExp | string) => string, + anyNumberOfTimes: (re: RegExp | string) => string + } + newInstance: () => HLJSApi + } + + interface ModesAPI { + SHEBANG: (mode?: Partial & { binary?: string | RegExp }) => Mode + BACKSLASH_ESCAPE: Mode + QUOTE_STRING_MODE: Mode + APOS_STRING_MODE: Mode + PHRASAL_WORDS_MODE: Mode + COMMENT: (begin: string | RegExp, end: string | RegExp, modeOpts?: Mode | {}) => Mode + C_LINE_COMMENT_MODE: Mode + C_BLOCK_COMMENT_MODE: Mode + HASH_COMMENT_MODE: Mode + NUMBER_MODE: Mode + C_NUMBER_MODE: Mode + BINARY_NUMBER_MODE: Mode + REGEXP_MODE: Mode + TITLE_MODE: Mode + UNDERSCORE_TITLE_MODE: Mode + METHOD_GUARD: Mode + END_SAME_AS_BEGIN: (mode: Mode) => Mode + // built in regex + IDENT_RE: string + UNDERSCORE_IDENT_RE: string + MATCH_NOTHING_RE: string + NUMBER_RE: string + C_NUMBER_RE: string + BINARY_NUMBER_RE: string + RE_STARTERS_RE: string + } + + export type LanguageFn = (hljs: HLJSApi) => Language + export type CompilerExt = (mode: Mode, parent: Mode | Language | null) => void + + export interface HighlightResult { + code?: string + relevance: number + value: string + language?: string + illegal: boolean + errorRaised?: Error + // * for auto-highlight + secondBest?: Omit + // private + _illegalBy?: illegalData + _emitter: Emitter + _top?: Language | CompiledMode + } + + export interface AutoHighlightResult extends HighlightResult { + } + + export interface illegalData { + message: string + context: string + index: number + resultSoFar: string + mode: CompiledMode + } + + export type BeforeHighlightContext = { + code: string, + language: string, + result?: HighlightResult + } + export type PluginEvent = keyof HLJSPlugin; + export type HLJSPlugin = { + 'after:highlight'?: (result: HighlightResult) => void, + 'before:highlight'?: (context: BeforeHighlightContext) => void, + 'after:highlightElement'?: (data: { el: Element, result: HighlightResult, text: string }) => void, + 'before:highlightElement'?: (data: { el: Element, language: string }) => void, + // TODO: Old API, remove with v12 + 'after:highlightBlock'?: (data: { + block: Element, + result: HighlightResult, + text: string + }) => void, + 'before:highlightBlock'?: (data: { block: Element, language: string }) => void, + } + + interface EmitterConstructor { + new(opts: any): Emitter + } + + export interface HighlightOptions { + language: string + ignoreIllegals?: boolean + } + + export interface HLJSOptions { + noHighlightRe: RegExp + languageDetectRe: RegExp + classPrefix: string + cssSelector: string + languages?: string[] + __emitter: EmitterConstructor + ignoreUnescapedHTML?: boolean + throwUnescapedHTML?: boolean + } + + export interface CallbackResponse { + data: Record + ignoreMatch: () => void + isMatchIgnored: boolean + } + + export type ModeCallback = (match: RegExpMatchArray, response: CallbackResponse) => void + export type Language = LanguageDetail & Partial + + export interface Mode extends ModeCallbacks, ModeDetails { + } + + export interface LanguageDetail { + name?: string + unicodeRegex?: boolean + rawDefinition?: () => Language + aliases?: string[] + disableAutodetect?: boolean + contains: (Mode)[] + case_insensitive?: boolean + keywords?: string | string[] | Record + isCompiled?: boolean, + exports?: any, + classNameAliases?: Record + compilerExtensions?: CompilerExt[] + supersetOf?: string + } + + // technically private, but exported for convenience as this has + // been a pretty stable API and is quite useful + export interface Emitter { + startScope(name: string): void + + endScope(): void + + addText(text: string): void + + toHTML(): string + + finalize(): void + + __addSublanguage(emitter: Emitter, subLanguageName: string): void + } + + export type HighlightedHTMLElement = HTMLElement & { + result?: object, + secondBest?: object, + parentNode: HTMLElement + } + + /* modes */ + + interface ModeCallbacks { + "on:end"?: Function, + "on:begin"?: ModeCallback + } + + export interface CompiledLanguage extends LanguageDetail, CompiledMode { + isCompiled: true + contains: CompiledMode[] + keywords: Record + } + + export type CompiledScope = Record & { + _emit?: Record, + _multi?: boolean, + _wrap?: string + }; + + export type CompiledMode = Omit & + { + begin?: RegExp | string + end?: RegExp | string + scope?: string + contains: CompiledMode[] + keywords: KeywordDict + data: Record + terminatorEnd: string + keywordPatternRe: RegExp + beginRe: RegExp + endRe: RegExp + illegalRe: RegExp + matcher: any + isCompiled: true + starts?: CompiledMode + parent?: CompiledMode + beginScope?: CompiledScope + endScope?: CompiledScope + } + + interface ModeDetails { + begin?: RegExp | string | (RegExp | string)[] + match?: RegExp | string | (RegExp | string)[] + end?: RegExp | string | (RegExp | string)[] + // deprecated in favor of \`scope\` + className?: string + scope?: string | Record + beginScope?: string | Record + endScope?: string | Record + contains?: ("self" | Mode)[] + endsParent?: boolean + endsWithParent?: boolean + endSameAsBegin?: boolean + skip?: boolean + excludeBegin?: boolean + excludeEnd?: boolean + returnBegin?: boolean + returnEnd?: boolean + __beforeBegin?: Function + parent?: Mode + starts?: Mode + lexemes?: string | RegExp + keywords?: string | string[] | Record + beginKeywords?: string + relevance?: number + illegal?: string | RegExp | Array + variants?: Mode[] + cachedVariants?: Mode[] + // parsed + subLanguage?: string | string[] + isCompiled?: boolean + label?: string + } + + const hljs: HLJSApi; + export default hljs; + + } + + declare module 'highlight.js/lib/languages/*' { + import {LanguageFn} from "highlight.js"; + const defineLanguage: LanguageFn; + export default defineLanguage; + } + `) + ); + }); + }); diff --git a/openrewrite/test/javascript/parser/typeLiteral.test.ts b/openrewrite/test/javascript/parser/typeLiteral.test.ts index 0dce89ab..78831eaa 100644 --- a/openrewrite/test/javascript/parser/typeLiteral.test.ts +++ b/openrewrite/test/javascript/parser/typeLiteral.test.ts @@ -28,6 +28,10 @@ describe('type literal mapping', () => { reset(): void; // Method [index: number]: string // Indexable add(): (x: number, y: number) => number; //Function signature + add: (x: number, y: number) => number; //Function type + add1: (x: number, y: number) => number; //Function type + ctroType: new < T > (x: number, y: number) => number; //Ctor type + ctroType1: new (x: number, y: number) => number; //Ctor type } `) ); diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java index 1ec43053..9e4aca3a 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptReceiver.java @@ -194,6 +194,7 @@ public JS.FunctionType visitFunctionType(JS.FunctionType functionType, ReceiverC functionType = functionType.withPrefix(ctx.receiveNonNullNode(functionType.getPrefix(), JavaScriptReceiver::receiveSpace)); functionType = functionType.withMarkers(ctx.receiveNonNullNode(functionType.getMarkers(), ctx::receiveMarkers)); functionType = functionType.getPadding().withConstructorType(ctx.receiveNonNullNode(functionType.getPadding().getConstructorType(), rightPaddedValueReceiver(java.lang.Boolean.class))); + functionType = functionType.withTypeParameters(ctx.receiveNode(functionType.getTypeParameters(), ctx::receiveTree)); functionType = functionType.getPadding().withParameters(ctx.receiveNonNullNode(functionType.getPadding().getParameters(), JavaScriptReceiver::receiveContainer)); functionType = functionType.withArrow(ctx.receiveNonNullNode(functionType.getArrow(), JavaScriptReceiver::receiveSpace)); functionType = functionType.withReturnType(ctx.receiveNonNullNode(functionType.getReturnType(), ctx::receiveTree)); @@ -1513,6 +1514,7 @@ public T create(Class type, ReceiverContext ctx) { ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), ctx.receiveNonNullNode(null, ctx::receiveMarkers), ctx.receiveNonNullNode(null, rightPaddedValueReceiver(java.lang.Boolean.class)), + ctx.receiveNode(null, ctx::receiveTree), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveContainer), ctx.receiveNonNullNode(null, JavaScriptReceiver::receiveSpace), ctx.receiveNonNullNode(null, ctx::receiveTree), diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java index 1aa8639b..b94b1940 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptSender.java @@ -177,6 +177,7 @@ public JS.FunctionType visitFunctionType(JS.FunctionType functionType, SenderCon ctx.sendNode(functionType, JS.FunctionType::getPrefix, JavaScriptSender::sendSpace); ctx.sendNode(functionType, JS.FunctionType::getMarkers, ctx::sendMarkers); ctx.sendNode(functionType, e -> e.getPadding().getConstructorType(), JavaScriptSender::sendRightPadded); + ctx.sendNode(functionType, JS.FunctionType::getTypeParameters, ctx::sendTree); ctx.sendNode(functionType, e -> e.getPadding().getParameters(), JavaScriptSender::sendContainer); ctx.sendNode(functionType, JS.FunctionType::getArrow, JavaScriptSender::sendSpace); ctx.sendNode(functionType, JS.FunctionType::getReturnType, ctx::sendTree); diff --git a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java index db2e869c..b0e33fe6 100644 --- a/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java +++ b/rewrite-javascript-remote/src/main/java/org/openrewrite/javascript/remote/JavaScriptValidator.java @@ -122,6 +122,7 @@ public JS.ExpressionWithTypeArguments visitExpressionWithTypeArguments(JS.Expres @Override public JS.FunctionType visitFunctionType(JS.FunctionType functionType, P p) { + visitAndValidate(functionType.getTypeParameters(), J.TypeParameters.class, p); visitAndValidate(functionType.getParameters(), Statement.class, p); visitAndValidate(functionType.getReturnType(), Expression.class, p); return functionType; diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptParser.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptParser.java index 76f3a983..020d1249 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptParser.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptParser.java @@ -96,7 +96,7 @@ public Stream parseInputs(Iterable inputs, @Nullable Path rel assert client != null; assert remotingContext != null; try (EncodingDetectingInputStream is = input.getSource(ctx)) { - SourceFile parsed = client.withNewSocket((socket, messenger) -> requireNonNull(messenger.sendRequest(generator -> { + SourceFile parsed = client.runUsingSocket((socket, messenger) -> requireNonNull(messenger.sendRequest(generator -> { if (input.isSynthetic() || !Files.isRegularFile(input.getPath())) { generator.writeString("parse-source"); generator.writeString(is.readFully()); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java index 78e6cdc3..dd052476 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/JavaScriptVisitor.java @@ -250,6 +250,7 @@ public J visitFunctionType(JS.FunctionType functionType, P p) { f = (JS.FunctionType) temp; } f = f.getPadding().withConstructorType(Objects.requireNonNull(visitRightPadded(f.getPadding().getConstructorType(), JsRightPadded.Location.FUNCTION_TYPE_CONSTRUCTOR, p))); + f = f.withTypeParameters(Objects.requireNonNull(visitAndCast(f.getTypeParameters(), p))); f = f.getPadding().withParameters(Objects.requireNonNull(visitContainer(f.getPadding().getParameters(), JContainer.Location.LANGUAGE_EXTENSION, p))); f = f.withParameters(ListUtils.map(f.getParameters(), e -> visitAndCast(e, p))); f = f.withArrow(visitSpace(f.getArrow(), JsSpace.Location.FUNCTION_TYPE_ARROW_PREFIX, p)); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java index 1787b74e..d7a00586 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/internal/JavaScriptPrinter.java @@ -195,6 +195,15 @@ public J visitFunctionType(JS.FunctionType functionType, PrintOutputCapture

p p.append("new"); visitRightPadded(functionType.getPadding().getConstructorType(), JsRightPadded.Location.FUNCTION_TYPE_CONSTRUCTOR, p); } + J.TypeParameters typeParameters = functionType.getTypeParameters(); + if (typeParameters != null) { + visit(typeParameters.getAnnotations(), p); + visitSpace(typeParameters.getPrefix(), Space.Location.TYPE_PARAMETERS, p); + visitMarkers(typeParameters.getMarkers(), p); + p.append("<"); + visitRightPadded(typeParameters.getPadding().getTypeParameters(), JRightPadded.Location.TYPE_PARAMETER, ",", p); + p.append(">"); + } visitContainer("(", functionType.getPadding().getParameters(), JsContainer.Location.FUNCTION_TYPE_PARAMETER, ",", ")", p); visitSpace(functionType.getArrow(), JsSpace.Location.FUNCTION_TYPE_ARROW_PREFIX, p); p.append("=>"); diff --git a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java index 3b84c59e..6f467ade 100644 --- a/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java +++ b/rewrite-javascript/src/main/java/org/openrewrite/javascript/tree/JS.java @@ -889,6 +889,10 @@ public FunctionType withConstructorType(boolean constructor) { return getPadding().withConstructorType(this.constructorType.withElement(constructor)); } + @Getter + @With + J.@Nullable TypeParameters typeParameters; + JContainer parameters; public List getParameters() { @@ -946,7 +950,8 @@ public JRightPadded getConstructorType() { } public FunctionType withConstructorType(JRightPadded constructor) { - return t.constructorType == constructor ? t : new FunctionType(t.id, t.prefix, t.markers, constructor, t.parameters, t.arrow, t.returnType, t.type); + return t.constructorType == constructor ? t : + new FunctionType(t.id, t.prefix, t.markers, constructor, t.typeParameters, t.parameters, t.arrow, t.returnType, t.type); } public JContainer getParameters() { @@ -954,7 +959,7 @@ public JContainer getParameters() { } public FunctionType withParameters(JContainer parameters) { - return t.parameters == parameters ? t : new FunctionType(t.id, t.prefix, t.markers, t.constructorType, parameters, t.arrow, t.returnType, t.type); + return t.parameters == parameters ? t : new FunctionType(t.id, t.prefix, t.markers, t.constructorType, t.typeParameters, parameters, t.arrow, t.returnType, t.type); } } }