@player-tools/typescript-expression-plugin 0.2.2--canary.20.519 → 0.4.0-next.2

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/index.cjs.js CHANGED
@@ -91,6 +91,47 @@ function convertExprToJSONNode(exprNode) {
91
91
  return jsoncParser.parseTree(JSON.stringify(val));
92
92
  }
93
93
 
94
+ var __defProp$1 = Object.defineProperty;
95
+ var __defProps$1 = Object.defineProperties;
96
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
97
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
98
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
99
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
100
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
101
+ var __spreadValues$1 = (a, b) => {
102
+ for (var prop in b || (b = {}))
103
+ if (__hasOwnProp$1.call(b, prop))
104
+ __defNormalProp$1(a, prop, b[prop]);
105
+ if (__getOwnPropSymbols$1)
106
+ for (var prop of __getOwnPropSymbols$1(b)) {
107
+ if (__propIsEnum$1.call(b, prop))
108
+ __defNormalProp$1(a, prop, b[prop]);
109
+ }
110
+ return a;
111
+ };
112
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
113
+ const toFunction = xlrSdk.simpleTransformGenerator("ref", "Expressions", (exp) => {
114
+ if (!exp.genericArguments || exp.ref !== "ExpressionHandler") {
115
+ return exp;
116
+ }
117
+ const [args, returnType] = exp.genericArguments;
118
+ const parameters = (args.type === "tuple" ? args.elementTypes : []).map((elementType, index) => {
119
+ var _a, _b, _c, _d, _e, _f;
120
+ return {
121
+ name: (_c = (_b = (_a = elementType.name) != null ? _a : elementType.type.name) != null ? _b : elementType.type.title) != null ? _c : `arg_${index}`,
122
+ type: __spreadValues$1({
123
+ name: (_f = (_e = (_d = elementType.name) != null ? _d : elementType.type.name) != null ? _e : elementType.type.title) != null ? _f : `arg_${index}`
124
+ }, elementType.type),
125
+ optional: elementType.optional === true ? elementType.optional : void 0
126
+ };
127
+ });
128
+ return __spreadProps$1(__spreadValues$1({}, exp), {
129
+ type: "function",
130
+ parameters,
131
+ returnType
132
+ });
133
+ });
134
+
94
135
  var __defProp = Object.defineProperty;
95
136
  var __defProps = Object.defineProperties;
96
137
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
@@ -110,66 +151,41 @@ var __spreadValues = (a, b) => {
110
151
  return a;
111
152
  };
112
153
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
113
- function reduceExpression(plugins) {
114
- const expressions = new Map();
115
- plugins.forEach((plugin) => {
116
- var _a;
117
- const { capabilities } = plugin;
118
- const registeredExpressions = (_a = capabilities == null ? void 0 : capabilities.Expressions) != null ? _a : [];
119
- registeredExpressions.forEach((exp) => {
120
- var _a2;
121
- if (exp.type !== "ref" || !exp.genericArguments) {
122
- return;
123
- }
124
- const expName = exp.name;
125
- const [args, returnType] = exp.genericArguments;
126
- const parameters = (args.type === "tuple" ? args.elementTypes : []).map((elementType, index) => {
127
- var _a3, _b, _c, _d, _e, _f;
128
- return {
129
- name: (_c = (_b = (_a3 = elementType.name) != null ? _a3 : elementType.type.name) != null ? _b : elementType.type.title) != null ? _c : `arg_${index}`,
130
- type: __spreadValues({
131
- name: (_f = (_e = (_d = elementType.name) != null ? _d : elementType.type.name) != null ? _e : elementType.type.title) != null ? _f : `arg_${index}`
132
- }, elementType.type),
133
- optional: elementType.optional === true ? elementType.optional : void 0
134
- };
135
- });
136
- const entry = {
137
- name: expName,
138
- description: (_a2 = exp.description) != null ? _a2 : "",
139
- source: plugin,
140
- type: __spreadProps(__spreadValues({}, exp), {
141
- type: "function",
142
- parameters,
143
- returnType
144
- })
145
- };
146
- expressions.set(expName, entry);
147
- });
148
- });
149
- const expList = {
150
- entries: expressions
151
- };
152
- return expList;
153
- }
154
154
  class ExpressionLanguageService {
155
155
  constructor(options) {
156
156
  this._plugins = [];
157
157
  var _a;
158
158
  this.logger = options == null ? void 0 : options.logger;
159
159
  this._plugins = (_a = options == null ? void 0 : options.plugins) != null ? _a : [];
160
- this._expressions = reduceExpression(this._plugins);
161
160
  this.xlr = new xlrSdk.XLRSDK();
162
161
  this._plugins.forEach((p) => {
163
- this.xlr.loadDefinitionsFromModule(p);
162
+ this.xlr.loadDefinitionsFromModule(p, void 0, [toFunction]);
164
163
  });
164
+ this._expressions = this.reduceExpression();
165
165
  }
166
166
  setConfig(config) {
167
167
  this._plugins = config.plugins;
168
- this._expressions = reduceExpression(this._plugins);
169
168
  this.xlr = new xlrSdk.XLRSDK();
170
169
  this._plugins.forEach((p) => {
171
- this.xlr.loadDefinitionsFromModule(p);
170
+ this.xlr.loadDefinitionsFromModule(p, void 0, [toFunction]);
171
+ });
172
+ this._expressions = this.reduceExpression();
173
+ }
174
+ reduceExpression() {
175
+ const expressions = new Map();
176
+ this.xlr.listTypes().forEach((type) => {
177
+ const typeInfo = this.xlr.getTypeInfo(type.name);
178
+ const source = this._plugins.find((value) => value.pluginName === (typeInfo == null ? void 0 : typeInfo.plugin));
179
+ if (type.type === "function" && (typeInfo == null ? void 0 : typeInfo.capability) === "Expressions" && source) {
180
+ expressions.set(type.name, {
181
+ name: type.name,
182
+ description: type.description,
183
+ type,
184
+ source
185
+ });
186
+ }
172
187
  });
188
+ return expressions;
173
189
  }
174
190
  getCompletionsAtPosition(context, position) {
175
191
  var _a, _b;
@@ -180,7 +196,7 @@ class ExpressionLanguageService {
180
196
  entries: []
181
197
  };
182
198
  if (context.text.length === 0) {
183
- this._expressions.entries.forEach((exp) => {
199
+ this._expressions.forEach((exp) => {
184
200
  completionInfo.entries.push({
185
201
  name: exp.name,
186
202
  kind: ts__namespace.ScriptElementKind.functionElement,
@@ -195,7 +211,7 @@ class ExpressionLanguageService {
195
211
  const parsed = player.parseExpression(line, { strict: false });
196
212
  const token = getTokenAtPosition(parsed, position);
197
213
  if ((token == null ? void 0 : token.type) === "Compound" && token.error) {
198
- this._expressions.entries.forEach((exp) => {
214
+ this._expressions.forEach((exp) => {
199
215
  completionInfo.entries.push({
200
216
  name: exp.name,
201
217
  kind: ts__namespace.ScriptElementKind.functionElement,
@@ -209,7 +225,7 @@ class ExpressionLanguageService {
209
225
  if ((token == null ? void 0 : token.type) === "Identifier") {
210
226
  const start = (_b = (_a = token.location) == null ? void 0 : _a.start) != null ? _b : { character: 0 };
211
227
  const wordFromStart = line.slice(start.character, position.character);
212
- const allCompletions = Array.from(this._expressions.entries.keys()).filter((key) => key.startsWith(wordFromStart));
228
+ const allCompletions = Array.from(this._expressions.keys()).filter((key) => key.startsWith(wordFromStart));
213
229
  allCompletions.forEach((c) => {
214
230
  completionInfo.entries.push({
215
231
  name: c,
@@ -224,7 +240,7 @@ class ExpressionLanguageService {
224
240
  }
225
241
  getCompletionEntryDetails(context, position, name) {
226
242
  var _a;
227
- const expression = this._expressions.entries.get(name);
243
+ const expression = this._expressions.get(name);
228
244
  const completionDetails = {
229
245
  name,
230
246
  kind: ts__namespace.ScriptElementKind.functionElement,
@@ -243,7 +259,7 @@ class ExpressionLanguageService {
243
259
  const parsed = player.parseExpression(context.text, { strict: false });
244
260
  const token = getTokenAtPosition(parsed, position);
245
261
  if ((token == null ? void 0 : token.type) === "Identifier") {
246
- const expression = this._expressions.entries.get(token.name);
262
+ const expression = this._expressions.get(token.name);
247
263
  if (expression) {
248
264
  const completionDetails = this.getCompletionEntryDetails(context, position, expression.name);
249
265
  return __spreadProps(__spreadValues({}, completionDetails), {
@@ -279,7 +295,7 @@ class ExpressionLanguageService {
279
295
  }
280
296
  if (node.type === "CallExpression") {
281
297
  const exprName = node.callTarget.name;
282
- const expression = this._expressions.entries.get(exprName);
298
+ const expression = this._expressions.get(exprName);
283
299
  node.args.forEach((n) => {
284
300
  diags.push(...this.getDiagnosticsForNode(context, n));
285
301
  });
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { decorateWithTemplateLanguageService } from 'typescript-template-language-service-decorator';
2
2
  import * as ts from 'typescript/lib/tsserverlibrary';
3
3
  import { createTSDocString } from '@player-tools/xlr-utils';
4
- import { XLRSDK } from '@player-tools/xlr-sdk';
4
+ import { simpleTransformGenerator, XLRSDK } from '@player-tools/xlr-sdk';
5
5
  import { parseExpression } from '@player-ui/player';
6
6
  import { parseTree } from 'jsonc-parser';
7
7
 
@@ -69,6 +69,47 @@ function convertExprToJSONNode(exprNode) {
69
69
  return parseTree(JSON.stringify(val));
70
70
  }
71
71
 
72
+ var __defProp$1 = Object.defineProperty;
73
+ var __defProps$1 = Object.defineProperties;
74
+ var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
75
+ var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
76
+ var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
77
+ var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
78
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
79
+ var __spreadValues$1 = (a, b) => {
80
+ for (var prop in b || (b = {}))
81
+ if (__hasOwnProp$1.call(b, prop))
82
+ __defNormalProp$1(a, prop, b[prop]);
83
+ if (__getOwnPropSymbols$1)
84
+ for (var prop of __getOwnPropSymbols$1(b)) {
85
+ if (__propIsEnum$1.call(b, prop))
86
+ __defNormalProp$1(a, prop, b[prop]);
87
+ }
88
+ return a;
89
+ };
90
+ var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
91
+ const toFunction = simpleTransformGenerator("ref", "Expressions", (exp) => {
92
+ if (!exp.genericArguments || exp.ref !== "ExpressionHandler") {
93
+ return exp;
94
+ }
95
+ const [args, returnType] = exp.genericArguments;
96
+ const parameters = (args.type === "tuple" ? args.elementTypes : []).map((elementType, index) => {
97
+ var _a, _b, _c, _d, _e, _f;
98
+ return {
99
+ name: (_c = (_b = (_a = elementType.name) != null ? _a : elementType.type.name) != null ? _b : elementType.type.title) != null ? _c : `arg_${index}`,
100
+ type: __spreadValues$1({
101
+ name: (_f = (_e = (_d = elementType.name) != null ? _d : elementType.type.name) != null ? _e : elementType.type.title) != null ? _f : `arg_${index}`
102
+ }, elementType.type),
103
+ optional: elementType.optional === true ? elementType.optional : void 0
104
+ };
105
+ });
106
+ return __spreadProps$1(__spreadValues$1({}, exp), {
107
+ type: "function",
108
+ parameters,
109
+ returnType
110
+ });
111
+ });
112
+
72
113
  var __defProp = Object.defineProperty;
73
114
  var __defProps = Object.defineProperties;
74
115
  var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
@@ -88,66 +129,41 @@ var __spreadValues = (a, b) => {
88
129
  return a;
89
130
  };
90
131
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
91
- function reduceExpression(plugins) {
92
- const expressions = new Map();
93
- plugins.forEach((plugin) => {
94
- var _a;
95
- const { capabilities } = plugin;
96
- const registeredExpressions = (_a = capabilities == null ? void 0 : capabilities.Expressions) != null ? _a : [];
97
- registeredExpressions.forEach((exp) => {
98
- var _a2;
99
- if (exp.type !== "ref" || !exp.genericArguments) {
100
- return;
101
- }
102
- const expName = exp.name;
103
- const [args, returnType] = exp.genericArguments;
104
- const parameters = (args.type === "tuple" ? args.elementTypes : []).map((elementType, index) => {
105
- var _a3, _b, _c, _d, _e, _f;
106
- return {
107
- name: (_c = (_b = (_a3 = elementType.name) != null ? _a3 : elementType.type.name) != null ? _b : elementType.type.title) != null ? _c : `arg_${index}`,
108
- type: __spreadValues({
109
- name: (_f = (_e = (_d = elementType.name) != null ? _d : elementType.type.name) != null ? _e : elementType.type.title) != null ? _f : `arg_${index}`
110
- }, elementType.type),
111
- optional: elementType.optional === true ? elementType.optional : void 0
112
- };
113
- });
114
- const entry = {
115
- name: expName,
116
- description: (_a2 = exp.description) != null ? _a2 : "",
117
- source: plugin,
118
- type: __spreadProps(__spreadValues({}, exp), {
119
- type: "function",
120
- parameters,
121
- returnType
122
- })
123
- };
124
- expressions.set(expName, entry);
125
- });
126
- });
127
- const expList = {
128
- entries: expressions
129
- };
130
- return expList;
131
- }
132
132
  class ExpressionLanguageService {
133
133
  constructor(options) {
134
134
  this._plugins = [];
135
135
  var _a;
136
136
  this.logger = options == null ? void 0 : options.logger;
137
137
  this._plugins = (_a = options == null ? void 0 : options.plugins) != null ? _a : [];
138
- this._expressions = reduceExpression(this._plugins);
139
138
  this.xlr = new XLRSDK();
140
139
  this._plugins.forEach((p) => {
141
- this.xlr.loadDefinitionsFromModule(p);
140
+ this.xlr.loadDefinitionsFromModule(p, void 0, [toFunction]);
142
141
  });
142
+ this._expressions = this.reduceExpression();
143
143
  }
144
144
  setConfig(config) {
145
145
  this._plugins = config.plugins;
146
- this._expressions = reduceExpression(this._plugins);
147
146
  this.xlr = new XLRSDK();
148
147
  this._plugins.forEach((p) => {
149
- this.xlr.loadDefinitionsFromModule(p);
148
+ this.xlr.loadDefinitionsFromModule(p, void 0, [toFunction]);
149
+ });
150
+ this._expressions = this.reduceExpression();
151
+ }
152
+ reduceExpression() {
153
+ const expressions = new Map();
154
+ this.xlr.listTypes().forEach((type) => {
155
+ const typeInfo = this.xlr.getTypeInfo(type.name);
156
+ const source = this._plugins.find((value) => value.pluginName === (typeInfo == null ? void 0 : typeInfo.plugin));
157
+ if (type.type === "function" && (typeInfo == null ? void 0 : typeInfo.capability) === "Expressions" && source) {
158
+ expressions.set(type.name, {
159
+ name: type.name,
160
+ description: type.description,
161
+ type,
162
+ source
163
+ });
164
+ }
150
165
  });
166
+ return expressions;
151
167
  }
152
168
  getCompletionsAtPosition(context, position) {
153
169
  var _a, _b;
@@ -158,7 +174,7 @@ class ExpressionLanguageService {
158
174
  entries: []
159
175
  };
160
176
  if (context.text.length === 0) {
161
- this._expressions.entries.forEach((exp) => {
177
+ this._expressions.forEach((exp) => {
162
178
  completionInfo.entries.push({
163
179
  name: exp.name,
164
180
  kind: ts.ScriptElementKind.functionElement,
@@ -173,7 +189,7 @@ class ExpressionLanguageService {
173
189
  const parsed = parseExpression(line, { strict: false });
174
190
  const token = getTokenAtPosition(parsed, position);
175
191
  if ((token == null ? void 0 : token.type) === "Compound" && token.error) {
176
- this._expressions.entries.forEach((exp) => {
192
+ this._expressions.forEach((exp) => {
177
193
  completionInfo.entries.push({
178
194
  name: exp.name,
179
195
  kind: ts.ScriptElementKind.functionElement,
@@ -187,7 +203,7 @@ class ExpressionLanguageService {
187
203
  if ((token == null ? void 0 : token.type) === "Identifier") {
188
204
  const start = (_b = (_a = token.location) == null ? void 0 : _a.start) != null ? _b : { character: 0 };
189
205
  const wordFromStart = line.slice(start.character, position.character);
190
- const allCompletions = Array.from(this._expressions.entries.keys()).filter((key) => key.startsWith(wordFromStart));
206
+ const allCompletions = Array.from(this._expressions.keys()).filter((key) => key.startsWith(wordFromStart));
191
207
  allCompletions.forEach((c) => {
192
208
  completionInfo.entries.push({
193
209
  name: c,
@@ -202,7 +218,7 @@ class ExpressionLanguageService {
202
218
  }
203
219
  getCompletionEntryDetails(context, position, name) {
204
220
  var _a;
205
- const expression = this._expressions.entries.get(name);
221
+ const expression = this._expressions.get(name);
206
222
  const completionDetails = {
207
223
  name,
208
224
  kind: ts.ScriptElementKind.functionElement,
@@ -221,7 +237,7 @@ class ExpressionLanguageService {
221
237
  const parsed = parseExpression(context.text, { strict: false });
222
238
  const token = getTokenAtPosition(parsed, position);
223
239
  if ((token == null ? void 0 : token.type) === "Identifier") {
224
- const expression = this._expressions.entries.get(token.name);
240
+ const expression = this._expressions.get(token.name);
225
241
  if (expression) {
226
242
  const completionDetails = this.getCompletionEntryDetails(context, position, expression.name);
227
243
  return __spreadProps(__spreadValues({}, completionDetails), {
@@ -257,7 +273,7 @@ class ExpressionLanguageService {
257
273
  }
258
274
  if (node.type === "CallExpression") {
259
275
  const exprName = node.callTarget.name;
260
- const expression = this._expressions.entries.get(exprName);
276
+ const expression = this._expressions.get(exprName);
261
277
  node.args.forEach((n) => {
262
278
  diags.push(...this.getDiagnosticsForNode(context, n));
263
279
  });
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@player-tools/typescript-expression-plugin",
3
- "version": "0.2.2--canary.20.519",
3
+ "version": "0.4.0-next.2",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org"
7
7
  },
8
8
  "peerDependencies": {},
9
9
  "dependencies": {
10
- "@player-tools/xlr": "0.2.2--canary.20.519",
11
- "@player-tools/xlr-sdk": "0.2.2--canary.20.519",
12
- "@player-tools/xlr-utils": "0.2.2--canary.20.519",
13
- "@player-ui/player": "0.3.1--canary.117.4130",
10
+ "@player-tools/xlr": "0.4.0-next.2",
11
+ "@player-tools/xlr-sdk": "0.4.0-next.2",
12
+ "@player-tools/xlr-utils": "0.4.0-next.2",
13
+ "@player-ui/player": "0.4.0-next.7",
14
14
  "jsonc-parser": "^2.3.1",
15
15
  "typescript-template-language-service-decorator": "^2.3.1",
16
16
  "@babel/runtime": "7.15.4"
package/src/service.ts CHANGED
@@ -4,12 +4,7 @@ import type {
4
4
  TemplateContext,
5
5
  Logger,
6
6
  } from 'typescript-template-language-service-decorator';
7
- import type {
8
- FunctionType,
9
- TSManifest,
10
- FunctionTypeParameters,
11
- NodeType,
12
- } from '@player-tools/xlr';
7
+ import type { FunctionType, TSManifest, NodeType } from '@player-tools/xlr';
13
8
  import { createTSDocString } from '@player-tools/xlr-utils';
14
9
  import { XLRSDK } from '@player-tools/xlr-sdk';
15
10
  import type { ExpressionNode } from '@player-ui/player';
@@ -19,90 +14,41 @@ import {
19
14
  toTSLocation,
20
15
  convertExprToJSONNode,
21
16
  } from './utils';
17
+ import { toFunction } from './transforms';
22
18
 
23
- interface ExpEntry {
19
+ interface ExpressionEntry {
20
+ /**
21
+ * The name of the expression
22
+ */
24
23
  name: string;
25
- description: string;
24
+ /**
25
+ * The description of the expression
26
+ */
27
+ description?: string;
28
+ /**
29
+ * The XLR type of the expression
30
+ */
26
31
  type: FunctionType;
32
+ /**
33
+ * The XLR enabled plugin the expression was sourced from
34
+ */
27
35
  source: TSManifest;
28
36
  }
29
37
 
30
- interface ExpressionList {
31
- entries: Map<string, ExpEntry>;
32
- }
33
-
34
38
  export interface ExpressionLanguageServiceConfig {
39
+ /**
40
+ * The list of XLR enabled plugins to load
41
+ */
35
42
  plugins: Array<TSManifest>;
36
43
  }
37
44
 
38
- // TODO: This should move into the xlr/cli package so expressions are converted to functions at build time
39
- function reduceExpression(plugins: Array<TSManifest>): ExpressionList {
40
- // Overlaps in names will be resolved by the last plugin to be loaded
41
- // So use a map to ensure no duplicates
42
- const expressions = new Map<string, ExpEntry>();
43
-
44
- plugins.forEach((plugin) => {
45
- const { capabilities } = plugin;
46
- const registeredExpressions = capabilities?.Expressions ?? [];
47
-
48
- registeredExpressions.forEach((exp) => {
49
- if (exp.type !== 'ref' || !exp.genericArguments) {
50
- return;
51
- }
52
-
53
- const expName = exp.name;
54
- const [args, returnType] = exp.genericArguments;
55
-
56
- const parameters: Array<FunctionTypeParameters> = (
57
- args.type === 'tuple' ? args.elementTypes : []
58
- ).map((elementType, index) => {
59
- return {
60
- name:
61
- elementType.name ??
62
- elementType.type.name ??
63
- elementType.type.title ??
64
- `arg_${index}`,
65
-
66
- type: {
67
- name:
68
- elementType.name ??
69
- elementType.type.name ??
70
- elementType.type.title ??
71
- `arg_${index}`,
72
- ...elementType.type,
73
- },
74
- optional:
75
- elementType.optional === true ? elementType.optional : undefined,
76
- };
77
- });
78
-
79
- const entry: ExpEntry = {
80
- name: expName,
81
- description: exp.description ?? '',
82
- source: plugin,
83
- type: {
84
- ...exp,
85
- type: 'function',
86
- parameters,
87
- returnType,
88
- },
89
- };
90
-
91
- expressions.set(expName, entry);
92
- });
93
- });
94
-
95
- const expList: ExpressionList = {
96
- entries: expressions,
97
- };
98
-
99
- return expList;
100
- }
101
-
45
+ /**
46
+ * Language server to check Player expression syntax and usage
47
+ */
102
48
  export class ExpressionLanguageService implements TemplateLanguageService {
103
49
  private logger?: Logger;
104
50
  private _plugins: Array<TSManifest> = [];
105
- private _expressions: ExpressionList;
51
+ private _expressions: Map<string, ExpressionEntry>;
106
52
  private xlr: XLRSDK;
107
53
 
108
54
  constructor(
@@ -110,22 +56,50 @@ export class ExpressionLanguageService implements TemplateLanguageService {
110
56
  ) {
111
57
  this.logger = options?.logger;
112
58
  this._plugins = options?.plugins ?? [];
113
- this._expressions = reduceExpression(this._plugins);
114
59
  this.xlr = new XLRSDK();
115
60
 
116
61
  this._plugins.forEach((p) => {
117
- this.xlr.loadDefinitionsFromModule(p);
62
+ this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);
118
63
  });
64
+ this._expressions = this.reduceExpression();
119
65
  }
120
66
 
121
67
  setConfig(config: ExpressionLanguageServiceConfig) {
122
68
  this._plugins = config.plugins;
123
- this._expressions = reduceExpression(this._plugins);
124
69
  this.xlr = new XLRSDK();
125
70
 
126
71
  this._plugins.forEach((p) => {
127
- this.xlr.loadDefinitionsFromModule(p);
72
+ this.xlr.loadDefinitionsFromModule(p, undefined, [toFunction]);
128
73
  });
74
+ this._expressions = this.reduceExpression();
75
+ }
76
+
77
+ private reduceExpression(): Map<string, ExpressionEntry> {
78
+ // Overlaps in names will be resolved by the last plugin to be loaded
79
+ // So use a map to ensure no duplicates
80
+ const expressions = new Map<string, ExpressionEntry>();
81
+
82
+ this.xlr.listTypes().forEach((type) => {
83
+ const typeInfo = this.xlr.getTypeInfo(type.name);
84
+ const source = this._plugins.find(
85
+ (value) => value.pluginName === typeInfo?.plugin
86
+ );
87
+
88
+ if (
89
+ type.type === 'function' &&
90
+ typeInfo?.capability === 'Expressions' &&
91
+ source
92
+ ) {
93
+ expressions.set(type.name, {
94
+ name: type.name,
95
+ description: type.description,
96
+ type: type as FunctionType,
97
+ source,
98
+ });
99
+ }
100
+ });
101
+
102
+ return expressions;
129
103
  }
130
104
 
131
105
  getCompletionsAtPosition(
@@ -143,7 +117,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
143
117
  // This happens for the start of an expression (e``)
144
118
  // Provide all the completions in this case
145
119
 
146
- this._expressions.entries.forEach((exp) => {
120
+ this._expressions.forEach((exp) => {
147
121
  completionInfo.entries.push({
148
122
  name: exp.name,
149
123
  kind: ts.ScriptElementKind.functionElement,
@@ -163,7 +137,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
163
137
  if (token?.type === 'Compound' && token.error) {
164
138
  // We hit the end of the expression, and it's expecting more
165
139
  // so provide all the completions
166
- this._expressions.entries.forEach((exp) => {
140
+ this._expressions.forEach((exp) => {
167
141
  completionInfo.entries.push({
168
142
  name: exp.name,
169
143
  kind: ts.ScriptElementKind.functionElement,
@@ -180,9 +154,9 @@ export class ExpressionLanguageService implements TemplateLanguageService {
180
154
  // get the relevant start of the identifier
181
155
  const start = token.location?.start ?? { character: 0 };
182
156
  const wordFromStart = line.slice(start.character, position.character);
183
- const allCompletions = Array.from(
184
- this._expressions.entries.keys()
185
- ).filter((key) => key.startsWith(wordFromStart));
157
+ const allCompletions = Array.from(this._expressions.keys()).filter(
158
+ (key) => key.startsWith(wordFromStart)
159
+ );
186
160
 
187
161
  allCompletions.forEach((c) => {
188
162
  completionInfo.entries.push({
@@ -203,7 +177,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
203
177
  position: ts.LineAndCharacter,
204
178
  name: string
205
179
  ): ts.CompletionEntryDetails {
206
- const expression = this._expressions.entries.get(name);
180
+ const expression = this._expressions.get(name);
207
181
 
208
182
  const completionDetails: ts.CompletionEntryDetails = {
209
183
  name,
@@ -230,7 +204,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
230
204
  const token = getTokenAtPosition(parsed, position);
231
205
 
232
206
  if (token?.type === 'Identifier') {
233
- const expression = this._expressions.entries.get(token.name);
207
+ const expression = this._expressions.get(token.name);
234
208
 
235
209
  if (expression) {
236
210
  const completionDetails = this.getCompletionEntryDetails(
@@ -289,7 +263,7 @@ export class ExpressionLanguageService implements TemplateLanguageService {
289
263
  if (node.type === 'CallExpression') {
290
264
  // Check that the expression is valid
291
265
  const exprName = node.callTarget.name;
292
- const expression = this._expressions.entries.get(exprName);
266
+ const expression = this._expressions.get(exprName);
293
267
 
294
268
  node.args.forEach((n) => {
295
269
  diags.push(...this.getDiagnosticsForNode(context, n));
@@ -0,0 +1,44 @@
1
+ import type { FunctionType, FunctionTypeParameters } from '@player-tools/xlr';
2
+ import { simpleTransformGenerator } from '@player-tools/xlr-sdk';
3
+
4
+ export const toFunction = simpleTransformGenerator(
5
+ 'ref',
6
+ 'Expressions',
7
+ (exp) => {
8
+ if (!exp.genericArguments || exp.ref !== 'ExpressionHandler') {
9
+ return exp;
10
+ }
11
+
12
+ const [args, returnType] = exp.genericArguments;
13
+
14
+ const parameters: Array<FunctionTypeParameters> = (
15
+ args.type === 'tuple' ? args.elementTypes : []
16
+ ).map((elementType, index) => {
17
+ return {
18
+ name:
19
+ elementType.name ??
20
+ elementType.type.name ??
21
+ elementType.type.title ??
22
+ `arg_${index}`,
23
+
24
+ type: {
25
+ name:
26
+ elementType.name ??
27
+ elementType.type.name ??
28
+ elementType.type.title ??
29
+ `arg_${index}`,
30
+ ...elementType.type,
31
+ },
32
+ optional:
33
+ elementType.optional === true ? elementType.optional : undefined,
34
+ };
35
+ });
36
+
37
+ return {
38
+ ...exp,
39
+ type: 'function',
40
+ parameters,
41
+ returnType,
42
+ } as FunctionType as any;
43
+ }
44
+ );