@player-tools/typescript-expression-plugin 0.10.0-next.0 → 0.10.0
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.
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/service.test.ts +3 -3
- package/src/index.ts +1 -1
- package/src/service.ts +9 -9
- package/src/transforms.ts +1 -1
- package/src/utils.ts +2 -2
- package/src/virtual-service-host.ts +1 -1
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -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"]}
|
package/dist/index.mjs.map
CHANGED
|
@@ -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
|
|
9
|
+
"version": "0.10.0",
|
|
10
10
|
"main": "dist/cjs/index.cjs",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@player-tools/xlr": "0.10.0
|
|
13
|
-
"@player-tools/xlr-sdk": "0.10.0
|
|
14
|
-
"@player-tools/xlr-utils": "0.10.0
|
|
15
|
-
"@player-ui/player": "0.
|
|
12
|
+
"@player-tools/xlr": "0.10.0",
|
|
13
|
+
"@player-tools/xlr-sdk": "0.10.0",
|
|
14
|
+
"@player-tools/xlr-utils": "0.10.0",
|
|
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
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
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;
|