@player-tools/typescript-expression-plugin 0.10.0-next.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/index.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/service.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/utils.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/transforms.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/logger.ts"],"sourcesContent":["import ts from \"typescript/lib/tsserverlibrary\";\nimport { decorateWithTemplateLanguageService } from \"typescript-template-language-service-decorator\";\nimport { ExpressionLanguageService } from \"./service\";\nimport { LSPLogger } from \"./logger\";\n\ninterface InitParams {\n typescript: typeof ts;\n}\nclass Plugin implements ts.server.PluginModule {\n private readonly initOptions: InitParams;\n private logger?: LSPLogger;\n private templateService?: ExpressionLanguageService;\n\n constructor(initOptions: InitParams) {\n this.initOptions = initOptions;\n }\n\n create(info: ts.server.PluginCreateInfo): ts.LanguageService {\n const logger = new LSPLogger(info);\n this.logger = logger;\n\n const templateService = new ExpressionLanguageService({ logger });\n this.templateService = templateService;\n\n return decorateWithTemplateLanguageService(\n this.initOptions.typescript,\n info.languageService,\n info.project,\n templateService,\n {\n tags: [\"e\", \"expr\", \"expression\"],\n enableForStringWithSubstitutions: true,\n },\n { logger }\n );\n }\n\n onConfigurationChanged(config: any) {\n this.templateService?.setConfig(config);\n }\n}\n\nfunction init(mod: InitParams): ts.server.PluginModule {\n return new Plugin(mod);\n}\n\nexport default init;\n// export = init;\n","import ts from \"typescript/lib/tsserverlibrary\";\nimport type {\n TemplateLanguageService,\n TemplateContext,\n Logger,\n} from \"typescript-template-language-service-decorator\";\nimport type { FunctionType, TSManifest, NodeType } from \"@player-tools/xlr\";\nimport { createTSDocString } from \"@player-tools/xlr-utils\";\nimport { XLRSDK } from \"@player-tools/xlr-sdk\";\nimport type { ExpressionNode } from \"@player-ui/player\";\nimport { parseExpression } from \"@player-ui/player\";\nimport {\n getTokenAtPosition,\n toTSLocation,\n convertExprToJSONNode,\n} from \"./utils\";\nimport { toFunction } from \"./transforms\";\n\ninterface ExpressionEntry {\n /**\n * The name of the expression\n */\n name: string;\n /**\n * The description of the expression\n */\n description?: string;\n /**\n * The XLR type of the expression\n */\n type: FunctionType;\n /**\n * The XLR enabled plugin the expression was sourced from\n */\n source: TSManifest;\n}\n\nexport interface ExpressionLanguageServiceConfig {\n /**\n * The list of XLR enabled plugins to load\n */\n plugins: Array<TSManifest>;\n}\n\n/**\n * Language server to check Player expression syntax and usage\n */\nexport class ExpressionLanguageService implements TemplateLanguageService {\n private logger?: Logger;\n private _plugins: Array<TSManifest> = [];\n private _expressions: Map<string, ExpressionEntry>;\n private xlr: XLRSDK;\n\n constructor(\n options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>\n ) {\n this.logger = options?.logger;\n this._plugins = options?.plugins ?? [];\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n setConfig(config: ExpressionLanguageServiceConfig) {\n this._plugins = config.plugins;\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n private reduceExpression(): Map<string, ExpressionEntry> {\n // Overlaps in names will be resolved by the last plugin to be loaded\n // So use a map to ensure no duplicates\n const expressions = new Map<string, ExpressionEntry>();\n\n this.xlr.listTypes().forEach((type) => {\n const typeInfo = this.xlr.getTypeInfo(type.name);\n const source = this._plugins.find(\n (value) => value.pluginName === typeInfo?.plugin\n );\n\n if (\n type.type === \"function\" &&\n typeInfo?.capability === \"Expressions\" &&\n source\n ) {\n expressions.set(type.name, {\n name: type.name,\n description: type.description,\n type: type as FunctionType,\n source,\n });\n }\n });\n\n return expressions;\n }\n\n getCompletionsAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter\n ): ts.CompletionInfo {\n const completionInfo: ts.CompletionInfo = {\n isGlobalCompletion: false,\n isMemberCompletion: false,\n isNewIdentifierLocation: true,\n entries: [],\n };\n\n if (context.text.length === 0) {\n // This happens for the start of an expression (e``)\n // Provide all the completions in this case\n\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n const line = context.text.split(/\\n/g)[position.line];\n const parsed = parseExpression(line, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Compound\" && token.error) {\n // We hit the end of the expression, and it's expecting more\n // so provide all the completions\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n if (token?.type === \"Identifier\") {\n // get the relevant start of the identifier\n const start = token.location?.start ?? { character: 0 };\n const wordFromStart = line.slice(start.character, position.character);\n const allCompletions = Array.from(this._expressions.keys()).filter(\n (key) => key.startsWith(wordFromStart)\n );\n\n allCompletions.forEach((c) => {\n completionInfo.entries.push({\n name: c,\n kind: ts.ScriptElementKind.functionElement,\n sortText: c,\n isRecommended: true,\n insertText: `${c}()`,\n });\n });\n }\n\n return completionInfo;\n }\n\n getCompletionEntryDetails(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n name: string\n ): ts.CompletionEntryDetails {\n const expression = this._expressions.get(name);\n\n const completionDetails: ts.CompletionEntryDetails = {\n name,\n kind: ts.ScriptElementKind.functionElement,\n kindModifiers: ts.ScriptElementKindModifier.none,\n\n documentation: [\n {\n kind: \"text\",\n text: expression?.type.description ?? \"\",\n },\n ],\n displayParts: expression ? createTSDocString(expression.type) : [],\n };\n\n return completionDetails;\n }\n\n getQuickInfoAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter\n ): ts.QuickInfo | undefined {\n const parsed = parseExpression(context.text, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Identifier\") {\n const expression = this._expressions.get(token.name);\n\n if (expression) {\n const completionDetails = this.getCompletionEntryDetails(\n context,\n position,\n expression.name\n );\n\n return {\n ...completionDetails,\n textSpan: toTSLocation(token),\n };\n }\n }\n\n return undefined;\n }\n\n private checkNode(\n context: TemplateContext,\n node: ExpressionNode,\n xlrType: NodeType\n ): ts.Diagnostic[] {\n const diagnostics: ts.Diagnostic[] = [];\n const asJsonNodeValue = convertExprToJSONNode(node);\n\n if (asJsonNodeValue) {\n const xlrDiags = this.xlr.validateByType(xlrType, asJsonNodeValue);\n\n xlrDiags.forEach((d) => {\n diagnostics.push({\n file: context.node.getSourceFile(),\n ...toTSLocation(node),\n messageText: d.message,\n category: ts.DiagnosticCategory.Error,\n code: 1,\n });\n });\n }\n\n return diagnostics;\n }\n\n private getDiagnosticsForNode(\n context: TemplateContext,\n node: ExpressionNode\n ): ts.Diagnostic[] {\n const diags: ts.Diagnostic[] = [];\n\n if (node.type === \"Compound\") {\n node.body.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n }\n\n if (node.type === \"CallExpression\") {\n // Check that the expression is valid\n const exprName = node.callTarget.name;\n const expression = this._expressions.get(exprName);\n\n node.args.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n\n if (expression) {\n // Double check the arguments match what we expect\n const expectedArgs = expression.type.parameters;\n const actualArgs = node.args;\n\n actualArgs.forEach((actualArg, index) => {\n const expectedArg = expectedArgs[index];\n\n if (expectedArg) {\n // Check that the type satisfies the expected type\n diags.push(...this.checkNode(context, actualArg, expectedArg.type));\n }\n });\n\n if (expectedArgs.length > actualArgs.length) {\n const requiredArgs = expectedArgs.filter((a) => !a.optional);\n if (actualArgs.length < requiredArgs.length) {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Expected ${requiredArgs.length} argument(s), got ${actualArgs.length}`,\n });\n }\n }\n } else {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Unknown expression ${exprName}`,\n });\n }\n }\n\n return diags;\n }\n\n getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n // Shortcut any type-checking if we don't have any info about what expressions are registered\n if (this._plugins.length === 0) {\n return [];\n }\n\n const parsed = parseExpression(context.text.trim(), { strict: false });\n return this.getDiagnosticsForNode(context, parsed);\n }\n\n getSyntacticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n const parsed = parseExpression(context.text.trim(), { strict: false });\n\n if (parsed.error) {\n return [\n {\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(parsed),\n messageText: parsed.error.message,\n },\n ];\n }\n\n return [];\n }\n}\n","import type { TextSpan } from \"typescript\";\nimport type { Position } from \"vscode-languageserver-types\";\nimport type { ExpressionNode, NodeLocation } from \"@player-ui/player\";\nimport { parseTree } from \"jsonc-parser\";\nimport type { Node } from \"jsonc-parser\";\n\n/** Check if the vscode position overlaps with the expression location */\nexport function isInRange(position: Position, location: NodeLocation) {\n return (\n position.character >= location.start.character &&\n position.character <= location.end.character\n );\n}\n\n/** Find the closest marked token at the given position */\nexport function getTokenAtPosition(\n node: ExpressionNode,\n position: Position\n): ExpressionNode | undefined {\n if (node.type === \"CallExpression\") {\n const anyArgs = node.args.find((arg) => {\n return getTokenAtPosition(arg, position);\n });\n\n if (anyArgs) {\n return anyArgs;\n }\n\n const asTarget = getTokenAtPosition(node.callTarget, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n if (node.type === \"Assignment\") {\n const asTarget =\n getTokenAtPosition(node.left, position) ??\n getTokenAtPosition(node.right, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n // Lastly check for yourself\n if (node.location && isInRange(position, node.location)) {\n return node;\n }\n}\n\n/** Get the location info that TS expects for it's diags */\nexport function toTSLocation(node: ExpressionNode): TextSpan {\n const start = node.location?.start.character;\n const end = node.location?.end.character;\n if (start === undefined || end === undefined) {\n return {\n start: 0,\n length: 0,\n };\n }\n\n return {\n start,\n length: end - start,\n };\n}\n\n/** ExpressionNode -> raw value */\nexport function convertExprToValue(exprNode: ExpressionNode): any {\n let val;\n\n if (exprNode.type === \"Literal\") {\n val = exprNode.value;\n } else if (exprNode.type === \"Object\") {\n val = {};\n exprNode.attributes.forEach((prop) => {\n val[convertExprToValue(prop.key)] = convertExprToValue(prop.value);\n });\n } else if (exprNode.type === \"ArrayExpression\") {\n val = exprNode.elements.map(convertExprToValue);\n }\n\n return val;\n}\n\n/** ExpressionNode -> JSONC Node */\nexport function convertExprToJSONNode(\n exprNode: ExpressionNode\n): Node | undefined {\n const val = convertExprToValue(exprNode);\n if (val === undefined) {\n return undefined;\n }\n\n return parseTree(JSON.stringify(val));\n}\n","import type { FunctionType, FunctionTypeParameters } from \"@player-tools/xlr\";\nimport { simpleTransformGenerator } from \"@player-tools/xlr-sdk\";\n\nexport const toFunction = simpleTransformGenerator(\n \"ref\",\n \"Expressions\",\n (exp) => {\n if (!exp.genericArguments || exp.ref !== \"ExpressionHandler\") {\n return exp;\n }\n\n const [args, returnType] = exp.genericArguments;\n\n const parameters: Array<FunctionTypeParameters> = (\n args.type === \"tuple\" ? args.elementTypes : []\n ).map((elementType, index) => {\n return {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n\n type: {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n ...elementType.type,\n },\n optional:\n elementType.optional === true ? elementType.optional : undefined,\n };\n });\n\n return {\n ...exp,\n type: \"function\",\n parameters,\n returnType,\n } as FunctionType as any;\n }\n);\n","import type { Logger } from \"typescript-template-language-service-decorator\";\nimport ts from \"typescript/lib/tsserverlibrary\";\n\nexport class LSPLogger implements Logger {\n private readonly info: ts.server.PluginCreateInfo;\n\n constructor(info: ts.server.PluginCreateInfo) {\n this.info = info;\n }\n\n log(msg: string) {\n this.info.project.projectService.logger.info(`[player-expr-lsp] ${msg}`);\n }\n}\n"],"mappings":"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","names":["import_xlr_sdk","ts"]}
1
+ {"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/index.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/service.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/utils.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/transforms.ts","../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/logger.ts"],"sourcesContent":["import ts from \"typescript/lib/tsserverlibrary\";\nimport { decorateWithTemplateLanguageService } from \"typescript-template-language-service-decorator\";\nimport { ExpressionLanguageService } from \"./service\";\nimport { LSPLogger } from \"./logger\";\n\ninterface InitParams {\n typescript: typeof ts;\n}\nclass Plugin implements ts.server.PluginModule {\n private readonly initOptions: InitParams;\n private logger?: LSPLogger;\n private templateService?: ExpressionLanguageService;\n\n constructor(initOptions: InitParams) {\n this.initOptions = initOptions;\n }\n\n create(info: ts.server.PluginCreateInfo): ts.LanguageService {\n const logger = new LSPLogger(info);\n this.logger = logger;\n\n const templateService = new ExpressionLanguageService({ logger });\n this.templateService = templateService;\n\n return decorateWithTemplateLanguageService(\n this.initOptions.typescript,\n info.languageService,\n info.project,\n templateService,\n {\n tags: [\"e\", \"expr\", \"expression\"],\n enableForStringWithSubstitutions: true,\n },\n { logger },\n );\n }\n\n onConfigurationChanged(config: any) {\n this.templateService?.setConfig(config);\n }\n}\n\nfunction init(mod: InitParams): ts.server.PluginModule {\n return new Plugin(mod);\n}\n\nexport default init;\n// export = init;\n","import ts from \"typescript/lib/tsserverlibrary\";\nimport type {\n TemplateLanguageService,\n TemplateContext,\n Logger,\n} from \"typescript-template-language-service-decorator\";\nimport type { FunctionType, TSManifest, NodeType } from \"@player-tools/xlr\";\nimport { createTSDocString } from \"@player-tools/xlr-utils\";\nimport { XLRSDK } from \"@player-tools/xlr-sdk\";\nimport type { ExpressionNode } from \"@player-ui/player\";\nimport { parseExpression } from \"@player-ui/player\";\nimport {\n getTokenAtPosition,\n toTSLocation,\n convertExprToJSONNode,\n} from \"./utils\";\nimport { toFunction } from \"./transforms\";\n\ninterface ExpressionEntry {\n /**\n * The name of the expression\n */\n name: string;\n /**\n * The description of the expression\n */\n description?: string;\n /**\n * The XLR type of the expression\n */\n type: FunctionType;\n /**\n * The XLR enabled plugin the expression was sourced from\n */\n source: TSManifest;\n}\n\nexport interface ExpressionLanguageServiceConfig {\n /**\n * The list of XLR enabled plugins to load\n */\n plugins: Array<TSManifest>;\n}\n\n/**\n * Language server to check Player expression syntax and usage\n */\nexport class ExpressionLanguageService implements TemplateLanguageService {\n private logger?: Logger;\n private _plugins: Array<TSManifest> = [];\n private _expressions: Map<string, ExpressionEntry>;\n private xlr: XLRSDK;\n\n constructor(\n options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>,\n ) {\n this.logger = options?.logger;\n this._plugins = options?.plugins ?? [];\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n setConfig(config: ExpressionLanguageServiceConfig) {\n this._plugins = config.plugins;\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n private reduceExpression(): Map<string, ExpressionEntry> {\n // Overlaps in names will be resolved by the last plugin to be loaded\n // So use a map to ensure no duplicates\n const expressions = new Map<string, ExpressionEntry>();\n\n this.xlr.listTypes().forEach((type) => {\n const typeInfo = this.xlr.getTypeInfo(type.name);\n const source = this._plugins.find(\n (value) => value.pluginName === typeInfo?.plugin,\n );\n\n if (\n type.type === \"function\" &&\n typeInfo?.capability === \"Expressions\" &&\n source\n ) {\n expressions.set(type.name, {\n name: type.name,\n description: type.description,\n type: type as FunctionType,\n source,\n });\n }\n });\n\n return expressions;\n }\n\n getCompletionsAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n ): ts.CompletionInfo {\n const completionInfo: ts.CompletionInfo = {\n isGlobalCompletion: false,\n isMemberCompletion: false,\n isNewIdentifierLocation: true,\n entries: [],\n };\n\n if (context.text.length === 0) {\n // This happens for the start of an expression (e``)\n // Provide all the completions in this case\n\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n const line = context.text.split(/\\n/g)[position.line];\n const parsed = parseExpression(line, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Compound\" && token.error) {\n // We hit the end of the expression, and it's expecting more\n // so provide all the completions\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n if (token?.type === \"Identifier\") {\n // get the relevant start of the identifier\n const start = token.location?.start ?? { character: 0 };\n const wordFromStart = line.slice(start.character, position.character);\n const allCompletions = Array.from(this._expressions.keys()).filter(\n (key) => key.startsWith(wordFromStart),\n );\n\n allCompletions.forEach((c) => {\n completionInfo.entries.push({\n name: c,\n kind: ts.ScriptElementKind.functionElement,\n sortText: c,\n isRecommended: true,\n insertText: `${c}()`,\n });\n });\n }\n\n return completionInfo;\n }\n\n getCompletionEntryDetails(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n name: string,\n ): ts.CompletionEntryDetails {\n const expression = this._expressions.get(name);\n\n const completionDetails: ts.CompletionEntryDetails = {\n name,\n kind: ts.ScriptElementKind.functionElement,\n kindModifiers: ts.ScriptElementKindModifier.none,\n\n documentation: [\n {\n kind: \"text\",\n text: expression?.type.description ?? \"\",\n },\n ],\n displayParts: expression ? createTSDocString(expression.type) : [],\n };\n\n return completionDetails;\n }\n\n getQuickInfoAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n ): ts.QuickInfo | undefined {\n const parsed = parseExpression(context.text, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Identifier\") {\n const expression = this._expressions.get(token.name);\n\n if (expression) {\n const completionDetails = this.getCompletionEntryDetails(\n context,\n position,\n expression.name,\n );\n\n return {\n ...completionDetails,\n textSpan: toTSLocation(token),\n };\n }\n }\n\n return undefined;\n }\n\n private checkNode(\n context: TemplateContext,\n node: ExpressionNode,\n xlrType: NodeType,\n ): ts.Diagnostic[] {\n const diagnostics: ts.Diagnostic[] = [];\n const asJsonNodeValue = convertExprToJSONNode(node);\n\n if (asJsonNodeValue) {\n const xlrDiags = this.xlr.validateByType(xlrType, asJsonNodeValue);\n\n xlrDiags.forEach((d) => {\n diagnostics.push({\n file: context.node.getSourceFile(),\n ...toTSLocation(node),\n messageText: d.message,\n category: ts.DiagnosticCategory.Error,\n code: 1,\n });\n });\n }\n\n return diagnostics;\n }\n\n private getDiagnosticsForNode(\n context: TemplateContext,\n node: ExpressionNode,\n ): ts.Diagnostic[] {\n const diags: ts.Diagnostic[] = [];\n\n if (node.type === \"Compound\") {\n node.body.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n }\n\n if (node.type === \"CallExpression\") {\n // Check that the expression is valid\n const exprName = node.callTarget.name;\n const expression = this._expressions.get(exprName);\n\n node.args.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n\n if (expression) {\n // Double check the arguments match what we expect\n const expectedArgs = expression.type.parameters;\n const actualArgs = node.args;\n\n actualArgs.forEach((actualArg, index) => {\n const expectedArg = expectedArgs[index];\n\n if (expectedArg) {\n // Check that the type satisfies the expected type\n diags.push(...this.checkNode(context, actualArg, expectedArg.type));\n }\n });\n\n if (expectedArgs.length > actualArgs.length) {\n const requiredArgs = expectedArgs.filter((a) => !a.optional);\n if (actualArgs.length < requiredArgs.length) {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Expected ${requiredArgs.length} argument(s), got ${actualArgs.length}`,\n });\n }\n }\n } else {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Unknown expression ${exprName}`,\n });\n }\n }\n\n return diags;\n }\n\n getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n // Shortcut any type-checking if we don't have any info about what expressions are registered\n if (this._plugins.length === 0) {\n return [];\n }\n\n const parsed = parseExpression(context.text.trim(), { strict: false });\n return this.getDiagnosticsForNode(context, parsed);\n }\n\n getSyntacticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n const parsed = parseExpression(context.text.trim(), { strict: false });\n\n if (parsed.error) {\n return [\n {\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(parsed),\n messageText: parsed.error.message,\n },\n ];\n }\n\n return [];\n }\n}\n","import type { TextSpan } from \"typescript\";\nimport type { Position } from \"vscode-languageserver-types\";\nimport type { ExpressionNode, NodeLocation } from \"@player-ui/player\";\nimport { parseTree } from \"jsonc-parser\";\nimport type { Node } from \"jsonc-parser\";\n\n/** Check if the vscode position overlaps with the expression location */\nexport function isInRange(position: Position, location: NodeLocation) {\n return (\n position.character >= location.start.character &&\n position.character <= location.end.character\n );\n}\n\n/** Find the closest marked token at the given position */\nexport function getTokenAtPosition(\n node: ExpressionNode,\n position: Position,\n): ExpressionNode | undefined {\n if (node.type === \"CallExpression\") {\n const anyArgs = node.args.find((arg) => {\n return getTokenAtPosition(arg, position);\n });\n\n if (anyArgs) {\n return anyArgs;\n }\n\n const asTarget = getTokenAtPosition(node.callTarget, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n if (node.type === \"Assignment\") {\n const asTarget =\n getTokenAtPosition(node.left, position) ??\n getTokenAtPosition(node.right, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n // Lastly check for yourself\n if (node.location && isInRange(position, node.location)) {\n return node;\n }\n}\n\n/** Get the location info that TS expects for it's diags */\nexport function toTSLocation(node: ExpressionNode): TextSpan {\n const start = node.location?.start.character;\n const end = node.location?.end.character;\n if (start === undefined || end === undefined) {\n return {\n start: 0,\n length: 0,\n };\n }\n\n return {\n start,\n length: end - start,\n };\n}\n\n/** ExpressionNode -> raw value */\nexport function convertExprToValue(exprNode: ExpressionNode): any {\n let val;\n\n if (exprNode.type === \"Literal\") {\n val = exprNode.value;\n } else if (exprNode.type === \"Object\") {\n val = {};\n exprNode.attributes.forEach((prop) => {\n val[convertExprToValue(prop.key)] = convertExprToValue(prop.value);\n });\n } else if (exprNode.type === \"ArrayExpression\") {\n val = exprNode.elements.map(convertExprToValue);\n }\n\n return val;\n}\n\n/** ExpressionNode -> JSONC Node */\nexport function convertExprToJSONNode(\n exprNode: ExpressionNode,\n): Node | undefined {\n const val = convertExprToValue(exprNode);\n if (val === undefined) {\n return undefined;\n }\n\n return parseTree(JSON.stringify(val));\n}\n","import type { FunctionType, FunctionTypeParameters } from \"@player-tools/xlr\";\nimport { simpleTransformGenerator } from \"@player-tools/xlr-sdk\";\n\nexport const toFunction = simpleTransformGenerator(\n \"ref\",\n \"Expressions\",\n (exp) => {\n if (!exp.genericArguments || exp.ref !== \"ExpressionHandler\") {\n return exp;\n }\n\n const [args, returnType] = exp.genericArguments;\n\n const parameters: Array<FunctionTypeParameters> = (\n args.type === \"tuple\" ? args.elementTypes : []\n ).map((elementType, index) => {\n return {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n\n type: {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n ...elementType.type,\n },\n optional:\n elementType.optional === true ? elementType.optional : undefined,\n };\n });\n\n return {\n ...exp,\n type: \"function\",\n parameters,\n returnType,\n } as FunctionType as any;\n },\n);\n","import type { Logger } from \"typescript-template-language-service-decorator\";\nimport ts from \"typescript/lib/tsserverlibrary\";\n\nexport class LSPLogger implements Logger {\n private readonly info: ts.server.PluginCreateInfo;\n\n constructor(info: ts.server.PluginCreateInfo) {\n this.info = info;\n }\n\n log(msg: string) {\n this.info.project.projectService.logger.info(`[player-expr-lsp] ${msg}`);\n }\n}\n"],"mappings":"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","names":["import_xlr_sdk","ts"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/index.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/service.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/utils.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/transforms.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/logger.ts"],"sourcesContent":["import ts from \"typescript/lib/tsserverlibrary\";\nimport { decorateWithTemplateLanguageService } from \"typescript-template-language-service-decorator\";\nimport { ExpressionLanguageService } from \"./service\";\nimport { LSPLogger } from \"./logger\";\n\ninterface InitParams {\n typescript: typeof ts;\n}\nclass Plugin implements ts.server.PluginModule {\n private readonly initOptions: InitParams;\n private logger?: LSPLogger;\n private templateService?: ExpressionLanguageService;\n\n constructor(initOptions: InitParams) {\n this.initOptions = initOptions;\n }\n\n create(info: ts.server.PluginCreateInfo): ts.LanguageService {\n const logger = new LSPLogger(info);\n this.logger = logger;\n\n const templateService = new ExpressionLanguageService({ logger });\n this.templateService = templateService;\n\n return decorateWithTemplateLanguageService(\n this.initOptions.typescript,\n info.languageService,\n info.project,\n templateService,\n {\n tags: [\"e\", \"expr\", \"expression\"],\n enableForStringWithSubstitutions: true,\n },\n { logger }\n );\n }\n\n onConfigurationChanged(config: any) {\n this.templateService?.setConfig(config);\n }\n}\n\nfunction init(mod: InitParams): ts.server.PluginModule {\n return new Plugin(mod);\n}\n\nexport default init;\n// export = init;\n","import ts from \"typescript/lib/tsserverlibrary\";\nimport type {\n TemplateLanguageService,\n TemplateContext,\n Logger,\n} from \"typescript-template-language-service-decorator\";\nimport type { FunctionType, TSManifest, NodeType } from \"@player-tools/xlr\";\nimport { createTSDocString } from \"@player-tools/xlr-utils\";\nimport { XLRSDK } from \"@player-tools/xlr-sdk\";\nimport type { ExpressionNode } from \"@player-ui/player\";\nimport { parseExpression } from \"@player-ui/player\";\nimport {\n getTokenAtPosition,\n toTSLocation,\n convertExprToJSONNode,\n} from \"./utils\";\nimport { toFunction } from \"./transforms\";\n\ninterface ExpressionEntry {\n /**\n * The name of the expression\n */\n name: string;\n /**\n * The description of the expression\n */\n description?: string;\n /**\n * The XLR type of the expression\n */\n type: FunctionType;\n /**\n * The XLR enabled plugin the expression was sourced from\n */\n source: TSManifest;\n}\n\nexport interface ExpressionLanguageServiceConfig {\n /**\n * The list of XLR enabled plugins to load\n */\n plugins: Array<TSManifest>;\n}\n\n/**\n * Language server to check Player expression syntax and usage\n */\nexport class ExpressionLanguageService implements TemplateLanguageService {\n private logger?: Logger;\n private _plugins: Array<TSManifest> = [];\n private _expressions: Map<string, ExpressionEntry>;\n private xlr: XLRSDK;\n\n constructor(\n options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>\n ) {\n this.logger = options?.logger;\n this._plugins = options?.plugins ?? [];\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n setConfig(config: ExpressionLanguageServiceConfig) {\n this._plugins = config.plugins;\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n private reduceExpression(): Map<string, ExpressionEntry> {\n // Overlaps in names will be resolved by the last plugin to be loaded\n // So use a map to ensure no duplicates\n const expressions = new Map<string, ExpressionEntry>();\n\n this.xlr.listTypes().forEach((type) => {\n const typeInfo = this.xlr.getTypeInfo(type.name);\n const source = this._plugins.find(\n (value) => value.pluginName === typeInfo?.plugin\n );\n\n if (\n type.type === \"function\" &&\n typeInfo?.capability === \"Expressions\" &&\n source\n ) {\n expressions.set(type.name, {\n name: type.name,\n description: type.description,\n type: type as FunctionType,\n source,\n });\n }\n });\n\n return expressions;\n }\n\n getCompletionsAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter\n ): ts.CompletionInfo {\n const completionInfo: ts.CompletionInfo = {\n isGlobalCompletion: false,\n isMemberCompletion: false,\n isNewIdentifierLocation: true,\n entries: [],\n };\n\n if (context.text.length === 0) {\n // This happens for the start of an expression (e``)\n // Provide all the completions in this case\n\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n const line = context.text.split(/\\n/g)[position.line];\n const parsed = parseExpression(line, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Compound\" && token.error) {\n // We hit the end of the expression, and it's expecting more\n // so provide all the completions\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n if (token?.type === \"Identifier\") {\n // get the relevant start of the identifier\n const start = token.location?.start ?? { character: 0 };\n const wordFromStart = line.slice(start.character, position.character);\n const allCompletions = Array.from(this._expressions.keys()).filter(\n (key) => key.startsWith(wordFromStart)\n );\n\n allCompletions.forEach((c) => {\n completionInfo.entries.push({\n name: c,\n kind: ts.ScriptElementKind.functionElement,\n sortText: c,\n isRecommended: true,\n insertText: `${c}()`,\n });\n });\n }\n\n return completionInfo;\n }\n\n getCompletionEntryDetails(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n name: string\n ): ts.CompletionEntryDetails {\n const expression = this._expressions.get(name);\n\n const completionDetails: ts.CompletionEntryDetails = {\n name,\n kind: ts.ScriptElementKind.functionElement,\n kindModifiers: ts.ScriptElementKindModifier.none,\n\n documentation: [\n {\n kind: \"text\",\n text: expression?.type.description ?? \"\",\n },\n ],\n displayParts: expression ? createTSDocString(expression.type) : [],\n };\n\n return completionDetails;\n }\n\n getQuickInfoAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter\n ): ts.QuickInfo | undefined {\n const parsed = parseExpression(context.text, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Identifier\") {\n const expression = this._expressions.get(token.name);\n\n if (expression) {\n const completionDetails = this.getCompletionEntryDetails(\n context,\n position,\n expression.name\n );\n\n return {\n ...completionDetails,\n textSpan: toTSLocation(token),\n };\n }\n }\n\n return undefined;\n }\n\n private checkNode(\n context: TemplateContext,\n node: ExpressionNode,\n xlrType: NodeType\n ): ts.Diagnostic[] {\n const diagnostics: ts.Diagnostic[] = [];\n const asJsonNodeValue = convertExprToJSONNode(node);\n\n if (asJsonNodeValue) {\n const xlrDiags = this.xlr.validateByType(xlrType, asJsonNodeValue);\n\n xlrDiags.forEach((d) => {\n diagnostics.push({\n file: context.node.getSourceFile(),\n ...toTSLocation(node),\n messageText: d.message,\n category: ts.DiagnosticCategory.Error,\n code: 1,\n });\n });\n }\n\n return diagnostics;\n }\n\n private getDiagnosticsForNode(\n context: TemplateContext,\n node: ExpressionNode\n ): ts.Diagnostic[] {\n const diags: ts.Diagnostic[] = [];\n\n if (node.type === \"Compound\") {\n node.body.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n }\n\n if (node.type === \"CallExpression\") {\n // Check that the expression is valid\n const exprName = node.callTarget.name;\n const expression = this._expressions.get(exprName);\n\n node.args.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n\n if (expression) {\n // Double check the arguments match what we expect\n const expectedArgs = expression.type.parameters;\n const actualArgs = node.args;\n\n actualArgs.forEach((actualArg, index) => {\n const expectedArg = expectedArgs[index];\n\n if (expectedArg) {\n // Check that the type satisfies the expected type\n diags.push(...this.checkNode(context, actualArg, expectedArg.type));\n }\n });\n\n if (expectedArgs.length > actualArgs.length) {\n const requiredArgs = expectedArgs.filter((a) => !a.optional);\n if (actualArgs.length < requiredArgs.length) {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Expected ${requiredArgs.length} argument(s), got ${actualArgs.length}`,\n });\n }\n }\n } else {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Unknown expression ${exprName}`,\n });\n }\n }\n\n return diags;\n }\n\n getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n // Shortcut any type-checking if we don't have any info about what expressions are registered\n if (this._plugins.length === 0) {\n return [];\n }\n\n const parsed = parseExpression(context.text.trim(), { strict: false });\n return this.getDiagnosticsForNode(context, parsed);\n }\n\n getSyntacticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n const parsed = parseExpression(context.text.trim(), { strict: false });\n\n if (parsed.error) {\n return [\n {\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(parsed),\n messageText: parsed.error.message,\n },\n ];\n }\n\n return [];\n }\n}\n","import type { TextSpan } from \"typescript\";\nimport type { Position } from \"vscode-languageserver-types\";\nimport type { ExpressionNode, NodeLocation } from \"@player-ui/player\";\nimport { parseTree } from \"jsonc-parser\";\nimport type { Node } from \"jsonc-parser\";\n\n/** Check if the vscode position overlaps with the expression location */\nexport function isInRange(position: Position, location: NodeLocation) {\n return (\n position.character >= location.start.character &&\n position.character <= location.end.character\n );\n}\n\n/** Find the closest marked token at the given position */\nexport function getTokenAtPosition(\n node: ExpressionNode,\n position: Position\n): ExpressionNode | undefined {\n if (node.type === \"CallExpression\") {\n const anyArgs = node.args.find((arg) => {\n return getTokenAtPosition(arg, position);\n });\n\n if (anyArgs) {\n return anyArgs;\n }\n\n const asTarget = getTokenAtPosition(node.callTarget, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n if (node.type === \"Assignment\") {\n const asTarget =\n getTokenAtPosition(node.left, position) ??\n getTokenAtPosition(node.right, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n // Lastly check for yourself\n if (node.location && isInRange(position, node.location)) {\n return node;\n }\n}\n\n/** Get the location info that TS expects for it's diags */\nexport function toTSLocation(node: ExpressionNode): TextSpan {\n const start = node.location?.start.character;\n const end = node.location?.end.character;\n if (start === undefined || end === undefined) {\n return {\n start: 0,\n length: 0,\n };\n }\n\n return {\n start,\n length: end - start,\n };\n}\n\n/** ExpressionNode -> raw value */\nexport function convertExprToValue(exprNode: ExpressionNode): any {\n let val;\n\n if (exprNode.type === \"Literal\") {\n val = exprNode.value;\n } else if (exprNode.type === \"Object\") {\n val = {};\n exprNode.attributes.forEach((prop) => {\n val[convertExprToValue(prop.key)] = convertExprToValue(prop.value);\n });\n } else if (exprNode.type === \"ArrayExpression\") {\n val = exprNode.elements.map(convertExprToValue);\n }\n\n return val;\n}\n\n/** ExpressionNode -> JSONC Node */\nexport function convertExprToJSONNode(\n exprNode: ExpressionNode\n): Node | undefined {\n const val = convertExprToValue(exprNode);\n if (val === undefined) {\n return undefined;\n }\n\n return parseTree(JSON.stringify(val));\n}\n","import type { FunctionType, FunctionTypeParameters } from \"@player-tools/xlr\";\nimport { simpleTransformGenerator } from \"@player-tools/xlr-sdk\";\n\nexport const toFunction = simpleTransformGenerator(\n \"ref\",\n \"Expressions\",\n (exp) => {\n if (!exp.genericArguments || exp.ref !== \"ExpressionHandler\") {\n return exp;\n }\n\n const [args, returnType] = exp.genericArguments;\n\n const parameters: Array<FunctionTypeParameters> = (\n args.type === \"tuple\" ? args.elementTypes : []\n ).map((elementType, index) => {\n return {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n\n type: {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n ...elementType.type,\n },\n optional:\n elementType.optional === true ? elementType.optional : undefined,\n };\n });\n\n return {\n ...exp,\n type: \"function\",\n parameters,\n returnType,\n } as FunctionType as any;\n }\n);\n","import type { Logger } from \"typescript-template-language-service-decorator\";\nimport ts from \"typescript/lib/tsserverlibrary\";\n\nexport class LSPLogger implements Logger {\n private readonly info: ts.server.PluginCreateInfo;\n\n constructor(info: ts.server.PluginCreateInfo) {\n this.info = info;\n }\n\n log(msg: string) {\n this.info.project.projectService.logger.info(`[player-expr-lsp] ${msg}`);\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/index.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/service.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/utils.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/transforms.ts","../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/language/typescript-expression-plugin/src/logger.ts"],"sourcesContent":["import ts from \"typescript/lib/tsserverlibrary\";\nimport { decorateWithTemplateLanguageService } from \"typescript-template-language-service-decorator\";\nimport { ExpressionLanguageService } from \"./service\";\nimport { LSPLogger } from \"./logger\";\n\ninterface InitParams {\n typescript: typeof ts;\n}\nclass Plugin implements ts.server.PluginModule {\n private readonly initOptions: InitParams;\n private logger?: LSPLogger;\n private templateService?: ExpressionLanguageService;\n\n constructor(initOptions: InitParams) {\n this.initOptions = initOptions;\n }\n\n create(info: ts.server.PluginCreateInfo): ts.LanguageService {\n const logger = new LSPLogger(info);\n this.logger = logger;\n\n const templateService = new ExpressionLanguageService({ logger });\n this.templateService = templateService;\n\n return decorateWithTemplateLanguageService(\n this.initOptions.typescript,\n info.languageService,\n info.project,\n templateService,\n {\n tags: [\"e\", \"expr\", \"expression\"],\n enableForStringWithSubstitutions: true,\n },\n { logger },\n );\n }\n\n onConfigurationChanged(config: any) {\n this.templateService?.setConfig(config);\n }\n}\n\nfunction init(mod: InitParams): ts.server.PluginModule {\n return new Plugin(mod);\n}\n\nexport default init;\n// export = init;\n","import ts from \"typescript/lib/tsserverlibrary\";\nimport type {\n TemplateLanguageService,\n TemplateContext,\n Logger,\n} from \"typescript-template-language-service-decorator\";\nimport type { FunctionType, TSManifest, NodeType } from \"@player-tools/xlr\";\nimport { createTSDocString } from \"@player-tools/xlr-utils\";\nimport { XLRSDK } from \"@player-tools/xlr-sdk\";\nimport type { ExpressionNode } from \"@player-ui/player\";\nimport { parseExpression } from \"@player-ui/player\";\nimport {\n getTokenAtPosition,\n toTSLocation,\n convertExprToJSONNode,\n} from \"./utils\";\nimport { toFunction } from \"./transforms\";\n\ninterface ExpressionEntry {\n /**\n * The name of the expression\n */\n name: string;\n /**\n * The description of the expression\n */\n description?: string;\n /**\n * The XLR type of the expression\n */\n type: FunctionType;\n /**\n * The XLR enabled plugin the expression was sourced from\n */\n source: TSManifest;\n}\n\nexport interface ExpressionLanguageServiceConfig {\n /**\n * The list of XLR enabled plugins to load\n */\n plugins: Array<TSManifest>;\n}\n\n/**\n * Language server to check Player expression syntax and usage\n */\nexport class ExpressionLanguageService implements TemplateLanguageService {\n private logger?: Logger;\n private _plugins: Array<TSManifest> = [];\n private _expressions: Map<string, ExpressionEntry>;\n private xlr: XLRSDK;\n\n constructor(\n options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>,\n ) {\n this.logger = options?.logger;\n this._plugins = options?.plugins ?? [];\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n setConfig(config: ExpressionLanguageServiceConfig) {\n this._plugins = config.plugins;\n this.xlr = new XLRSDK();\n\n this._plugins.forEach((p) => {\n this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);\n });\n this._expressions = this.reduceExpression();\n }\n\n private reduceExpression(): Map<string, ExpressionEntry> {\n // Overlaps in names will be resolved by the last plugin to be loaded\n // So use a map to ensure no duplicates\n const expressions = new Map<string, ExpressionEntry>();\n\n this.xlr.listTypes().forEach((type) => {\n const typeInfo = this.xlr.getTypeInfo(type.name);\n const source = this._plugins.find(\n (value) => value.pluginName === typeInfo?.plugin,\n );\n\n if (\n type.type === \"function\" &&\n typeInfo?.capability === \"Expressions\" &&\n source\n ) {\n expressions.set(type.name, {\n name: type.name,\n description: type.description,\n type: type as FunctionType,\n source,\n });\n }\n });\n\n return expressions;\n }\n\n getCompletionsAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n ): ts.CompletionInfo {\n const completionInfo: ts.CompletionInfo = {\n isGlobalCompletion: false,\n isMemberCompletion: false,\n isNewIdentifierLocation: true,\n entries: [],\n };\n\n if (context.text.length === 0) {\n // This happens for the start of an expression (e``)\n // Provide all the completions in this case\n\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n const line = context.text.split(/\\n/g)[position.line];\n const parsed = parseExpression(line, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Compound\" && token.error) {\n // We hit the end of the expression, and it's expecting more\n // so provide all the completions\n this._expressions.forEach((exp) => {\n completionInfo.entries.push({\n name: exp.name,\n kind: ts.ScriptElementKind.functionElement,\n sortText: exp.name,\n isRecommended: true,\n insertText: `${exp.name}()`,\n });\n });\n\n return completionInfo;\n }\n\n if (token?.type === \"Identifier\") {\n // get the relevant start of the identifier\n const start = token.location?.start ?? { character: 0 };\n const wordFromStart = line.slice(start.character, position.character);\n const allCompletions = Array.from(this._expressions.keys()).filter(\n (key) => key.startsWith(wordFromStart),\n );\n\n allCompletions.forEach((c) => {\n completionInfo.entries.push({\n name: c,\n kind: ts.ScriptElementKind.functionElement,\n sortText: c,\n isRecommended: true,\n insertText: `${c}()`,\n });\n });\n }\n\n return completionInfo;\n }\n\n getCompletionEntryDetails(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n name: string,\n ): ts.CompletionEntryDetails {\n const expression = this._expressions.get(name);\n\n const completionDetails: ts.CompletionEntryDetails = {\n name,\n kind: ts.ScriptElementKind.functionElement,\n kindModifiers: ts.ScriptElementKindModifier.none,\n\n documentation: [\n {\n kind: \"text\",\n text: expression?.type.description ?? \"\",\n },\n ],\n displayParts: expression ? createTSDocString(expression.type) : [],\n };\n\n return completionDetails;\n }\n\n getQuickInfoAtPosition(\n context: TemplateContext,\n position: ts.LineAndCharacter,\n ): ts.QuickInfo | undefined {\n const parsed = parseExpression(context.text, { strict: false });\n const token = getTokenAtPosition(parsed, position);\n\n if (token?.type === \"Identifier\") {\n const expression = this._expressions.get(token.name);\n\n if (expression) {\n const completionDetails = this.getCompletionEntryDetails(\n context,\n position,\n expression.name,\n );\n\n return {\n ...completionDetails,\n textSpan: toTSLocation(token),\n };\n }\n }\n\n return undefined;\n }\n\n private checkNode(\n context: TemplateContext,\n node: ExpressionNode,\n xlrType: NodeType,\n ): ts.Diagnostic[] {\n const diagnostics: ts.Diagnostic[] = [];\n const asJsonNodeValue = convertExprToJSONNode(node);\n\n if (asJsonNodeValue) {\n const xlrDiags = this.xlr.validateByType(xlrType, asJsonNodeValue);\n\n xlrDiags.forEach((d) => {\n diagnostics.push({\n file: context.node.getSourceFile(),\n ...toTSLocation(node),\n messageText: d.message,\n category: ts.DiagnosticCategory.Error,\n code: 1,\n });\n });\n }\n\n return diagnostics;\n }\n\n private getDiagnosticsForNode(\n context: TemplateContext,\n node: ExpressionNode,\n ): ts.Diagnostic[] {\n const diags: ts.Diagnostic[] = [];\n\n if (node.type === \"Compound\") {\n node.body.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n }\n\n if (node.type === \"CallExpression\") {\n // Check that the expression is valid\n const exprName = node.callTarget.name;\n const expression = this._expressions.get(exprName);\n\n node.args.forEach((n) => {\n diags.push(...this.getDiagnosticsForNode(context, n));\n });\n\n if (expression) {\n // Double check the arguments match what we expect\n const expectedArgs = expression.type.parameters;\n const actualArgs = node.args;\n\n actualArgs.forEach((actualArg, index) => {\n const expectedArg = expectedArgs[index];\n\n if (expectedArg) {\n // Check that the type satisfies the expected type\n diags.push(...this.checkNode(context, actualArg, expectedArg.type));\n }\n });\n\n if (expectedArgs.length > actualArgs.length) {\n const requiredArgs = expectedArgs.filter((a) => !a.optional);\n if (actualArgs.length < requiredArgs.length) {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Expected ${requiredArgs.length} argument(s), got ${actualArgs.length}`,\n });\n }\n }\n } else {\n diags.push({\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(node.callTarget),\n messageText: `Unknown expression ${exprName}`,\n });\n }\n }\n\n return diags;\n }\n\n getSemanticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n // Shortcut any type-checking if we don't have any info about what expressions are registered\n if (this._plugins.length === 0) {\n return [];\n }\n\n const parsed = parseExpression(context.text.trim(), { strict: false });\n return this.getDiagnosticsForNode(context, parsed);\n }\n\n getSyntacticDiagnostics(context: TemplateContext): ts.Diagnostic[] {\n const parsed = parseExpression(context.text.trim(), { strict: false });\n\n if (parsed.error) {\n return [\n {\n category: ts.DiagnosticCategory.Error,\n code: 1,\n file: context.node.getSourceFile(),\n ...toTSLocation(parsed),\n messageText: parsed.error.message,\n },\n ];\n }\n\n return [];\n }\n}\n","import type { TextSpan } from \"typescript\";\nimport type { Position } from \"vscode-languageserver-types\";\nimport type { ExpressionNode, NodeLocation } from \"@player-ui/player\";\nimport { parseTree } from \"jsonc-parser\";\nimport type { Node } from \"jsonc-parser\";\n\n/** Check if the vscode position overlaps with the expression location */\nexport function isInRange(position: Position, location: NodeLocation) {\n return (\n position.character >= location.start.character &&\n position.character <= location.end.character\n );\n}\n\n/** Find the closest marked token at the given position */\nexport function getTokenAtPosition(\n node: ExpressionNode,\n position: Position,\n): ExpressionNode | undefined {\n if (node.type === \"CallExpression\") {\n const anyArgs = node.args.find((arg) => {\n return getTokenAtPosition(arg, position);\n });\n\n if (anyArgs) {\n return anyArgs;\n }\n\n const asTarget = getTokenAtPosition(node.callTarget, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n if (node.type === \"Assignment\") {\n const asTarget =\n getTokenAtPosition(node.left, position) ??\n getTokenAtPosition(node.right, position);\n if (asTarget) {\n return asTarget;\n }\n }\n\n // Lastly check for yourself\n if (node.location && isInRange(position, node.location)) {\n return node;\n }\n}\n\n/** Get the location info that TS expects for it's diags */\nexport function toTSLocation(node: ExpressionNode): TextSpan {\n const start = node.location?.start.character;\n const end = node.location?.end.character;\n if (start === undefined || end === undefined) {\n return {\n start: 0,\n length: 0,\n };\n }\n\n return {\n start,\n length: end - start,\n };\n}\n\n/** ExpressionNode -> raw value */\nexport function convertExprToValue(exprNode: ExpressionNode): any {\n let val;\n\n if (exprNode.type === \"Literal\") {\n val = exprNode.value;\n } else if (exprNode.type === \"Object\") {\n val = {};\n exprNode.attributes.forEach((prop) => {\n val[convertExprToValue(prop.key)] = convertExprToValue(prop.value);\n });\n } else if (exprNode.type === \"ArrayExpression\") {\n val = exprNode.elements.map(convertExprToValue);\n }\n\n return val;\n}\n\n/** ExpressionNode -> JSONC Node */\nexport function convertExprToJSONNode(\n exprNode: ExpressionNode,\n): Node | undefined {\n const val = convertExprToValue(exprNode);\n if (val === undefined) {\n return undefined;\n }\n\n return parseTree(JSON.stringify(val));\n}\n","import type { FunctionType, FunctionTypeParameters } from \"@player-tools/xlr\";\nimport { simpleTransformGenerator } from \"@player-tools/xlr-sdk\";\n\nexport const toFunction = simpleTransformGenerator(\n \"ref\",\n \"Expressions\",\n (exp) => {\n if (!exp.genericArguments || exp.ref !== \"ExpressionHandler\") {\n return exp;\n }\n\n const [args, returnType] = exp.genericArguments;\n\n const parameters: Array<FunctionTypeParameters> = (\n args.type === \"tuple\" ? args.elementTypes : []\n ).map((elementType, index) => {\n return {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n\n type: {\n name:\n elementType.name ??\n elementType.type.name ??\n elementType.type.title ??\n `arg_${index}`,\n ...elementType.type,\n },\n optional:\n elementType.optional === true ? elementType.optional : undefined,\n };\n });\n\n return {\n ...exp,\n type: \"function\",\n parameters,\n returnType,\n } as FunctionType as any;\n },\n);\n","import type { Logger } from \"typescript-template-language-service-decorator\";\nimport ts from \"typescript/lib/tsserverlibrary\";\n\nexport class LSPLogger implements Logger {\n private readonly info: ts.server.PluginCreateInfo;\n\n constructor(info: ts.server.PluginCreateInfo) {\n this.info = info;\n }\n\n log(msg: string) {\n this.info.project.projectService.logger.info(`[player-expr-lsp] ${msg}`);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -6,13 +6,13 @@
6
6
  "types"
7
7
  ],
8
8
  "name": "@player-tools/typescript-expression-plugin",
9
- "version": "0.10.0-next.0",
9
+ "version": "0.10.1",
10
10
  "main": "dist/cjs/index.cjs",
11
11
  "dependencies": {
12
- "@player-tools/xlr": "0.10.0-next.0",
13
- "@player-tools/xlr-sdk": "0.10.0-next.0",
14
- "@player-tools/xlr-utils": "0.10.0-next.0",
15
- "@player-ui/player": "0.7.3",
12
+ "@player-tools/xlr": "0.10.1",
13
+ "@player-tools/xlr-sdk": "0.10.1",
14
+ "@player-tools/xlr-utils": "0.10.1",
15
+ "@player-ui/player": "0.10.4",
16
16
  "jsonc-parser": "^2.3.1",
17
17
  "typescript-template-language-service-decorator": "^2.3.1",
18
18
  "vscode-languageserver-types": "^3.15.1",
@@ -18,7 +18,7 @@ describe("language-service", () => {
18
18
  {
19
19
  line: 0,
20
20
  character: 1,
21
- }
21
+ },
22
22
  );
23
23
 
24
24
  expect(completions).toMatchInlineSnapshot(`
@@ -174,11 +174,11 @@ describe("language-service", () => {
174
174
  {
175
175
  line: 0,
176
176
  character: 0,
177
- }
177
+ },
178
178
  );
179
179
 
180
180
  expect(
181
- symbolDisplayToString(info?.displayParts as ts.SymbolDisplayPart[])
181
+ symbolDisplayToString(info?.displayParts as ts.SymbolDisplayPart[]),
182
182
  ).toMatchInlineSnapshot(`"function trim(arg: unknown): unknown"`);
183
183
  });
184
184
  });
package/src/index.ts CHANGED
@@ -31,7 +31,7 @@ class Plugin implements ts.server.PluginModule {
31
31
  tags: ["e", "expr", "expression"],
32
32
  enableForStringWithSubstitutions: true,
33
33
  },
34
- { logger }
34
+ { logger },
35
35
  );
36
36
  }
37
37
 
package/src/service.ts CHANGED
@@ -52,7 +52,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
52
52
  private xlr: XLRSDK;
53
53
 
54
54
  constructor(
55
- options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>
55
+ options?: { logger?: Logger } & Partial<ExpressionLanguageServiceConfig>,
56
56
  ) {
57
57
  this.logger = options?.logger;
58
58
  this._plugins = options?.plugins ?? [];
@@ -82,7 +82,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
82
82
  this.xlr.listTypes().forEach((type) => {
83
83
  const typeInfo = this.xlr.getTypeInfo(type.name);
84
84
  const source = this._plugins.find(
85
- (value) => value.pluginName === typeInfo?.plugin
85
+ (value) => value.pluginName === typeInfo?.plugin,
86
86
  );
87
87
 
88
88
  if (
@@ -104,7 +104,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
104
104
 
105
105
  getCompletionsAtPosition(
106
106
  context: TemplateContext,
107
- position: ts.LineAndCharacter
107
+ position: ts.LineAndCharacter,
108
108
  ): ts.CompletionInfo {
109
109
  const completionInfo: ts.CompletionInfo = {
110
110
  isGlobalCompletion: false,
@@ -155,7 +155,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
155
155
  const start = token.location?.start ?? { character: 0 };
156
156
  const wordFromStart = line.slice(start.character, position.character);
157
157
  const allCompletions = Array.from(this._expressions.keys()).filter(
158
- (key) => key.startsWith(wordFromStart)
158
+ (key) => key.startsWith(wordFromStart),
159
159
  );
160
160
 
161
161
  allCompletions.forEach((c) => {
@@ -175,7 +175,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
175
175
  getCompletionEntryDetails(
176
176
  context: TemplateContext,
177
177
  position: ts.LineAndCharacter,
178
- name: string
178
+ name: string,
179
179
  ): ts.CompletionEntryDetails {
180
180
  const expression = this._expressions.get(name);
181
181
 
@@ -198,7 +198,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
198
198
 
199
199
  getQuickInfoAtPosition(
200
200
  context: TemplateContext,
201
- position: ts.LineAndCharacter
201
+ position: ts.LineAndCharacter,
202
202
  ): ts.QuickInfo | undefined {
203
203
  const parsed = parseExpression(context.text, { strict: false });
204
204
  const token = getTokenAtPosition(parsed, position);
@@ -210,7 +210,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
210
210
  const completionDetails = this.getCompletionEntryDetails(
211
211
  context,
212
212
  position,
213
- expression.name
213
+ expression.name,
214
214
  );
215
215
 
216
216
  return {
@@ -226,7 +226,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
226
226
  private checkNode(
227
227
  context: TemplateContext,
228
228
  node: ExpressionNode,
229
- xlrType: NodeType
229
+ xlrType: NodeType,
230
230
  ): ts.Diagnostic[] {
231
231
  const diagnostics: ts.Diagnostic[] = [];
232
232
  const asJsonNodeValue = convertExprToJSONNode(node);
@@ -250,7 +250,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
250
250
 
251
251
  private getDiagnosticsForNode(
252
252
  context: TemplateContext,
253
- node: ExpressionNode
253
+ node: ExpressionNode,
254
254
  ): ts.Diagnostic[] {
255
255
  const diags: ts.Diagnostic[] = [];
256
256
 
package/src/transforms.ts CHANGED
@@ -40,5 +40,5 @@ export const toFunction = simpleTransformGenerator(
40
40
  parameters,
41
41
  returnType,
42
42
  } as FunctionType as any;
43
- }
43
+ },
44
44
  );
package/src/utils.ts CHANGED
@@ -15,7 +15,7 @@ export function isInRange(position: Position, location: NodeLocation) {
15
15
  /** Find the closest marked token at the given position */
16
16
  export function getTokenAtPosition(
17
17
  node: ExpressionNode,
18
- position: Position
18
+ position: Position,
19
19
  ): ExpressionNode | undefined {
20
20
  if (node.type === "CallExpression") {
21
21
  const anyArgs = node.args.find((arg) => {
@@ -84,7 +84,7 @@ export function convertExprToValue(exprNode: ExpressionNode): any {
84
84
 
85
85
  /** ExpressionNode -> JSONC Node */
86
86
  export function convertExprToJSONNode(
87
- exprNode: ExpressionNode
87
+ exprNode: ExpressionNode,
88
88
  ): Node | undefined {
89
89
  const val = convertExprToValue(exprNode);
90
90
  if (val === undefined) {
@@ -9,7 +9,7 @@ export default class VirtualServiceHost implements ts.LanguageServiceHost {
9
9
  constructor(
10
10
  typescript: typeof ts,
11
11
  compilerOptions: ts.CompilerOptions,
12
- workspacePath: string
12
+ workspacePath: string,
13
13
  ) {
14
14
  this.typescript = typescript;
15
15
  this.compilerOptions = compilerOptions;