@komaci/esm-generator 240.1.3 → 242.1.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.
Files changed (48) hide show
  1. package/build/__tests__/adgAstGeneration.spec.d.ts +2 -0
  2. package/build/__tests__/adgAstGeneration.spec.js +31 -0
  3. package/build/__tests__/compositionAstGeneration.spec.d.ts +2 -0
  4. package/build/__tests__/compositionAstGeneration.spec.js +394 -0
  5. package/build/__tests__/fixtures-combined-files/exclude-partial-classProps-indirect-importRef-getter/actual.js +5 -1
  6. package/build/__tests__/fixtures-combined-files/include-all-indirect-importRef-getter-complex/actual.js +5 -1
  7. package/build/__tests__/fixtures-combined-files/include-class-prop-indirect-importRef-getter/actual.js +5 -1
  8. package/build/__tests__/fixtures-script-files/imports/actual.js +5 -1
  9. package/build/__tests__/fixtures-script-files/imports-namespaced/actual.js +5 -1
  10. package/build/__tests__/fixtures-script-files/wire-imports/actual.js +5 -1
  11. package/build/__tests__/functionAstGeneration.spec.d.ts +2 -0
  12. package/build/__tests__/functionAstGeneration.spec.js +412 -0
  13. package/build/__tests__/general-komaci-docs/import-types/source.js +5 -1
  14. package/build/__tests__/general-komaci-docs/template-component/source.js +3 -3
  15. package/build/__tests__/genericAstGeneration.spec.d.ts +2 -0
  16. package/build/__tests__/genericAstGeneration.spec.js +586 -0
  17. package/build/__tests__/index.spec.js +13 -9
  18. package/build/__tests__/komaci-ast-unit.spec.js +240 -448
  19. package/build/__tests__/komaci-bundle-module.fixtures.spec.js +1 -0
  20. package/build/__tests__/komaci-script-module.fixtures.spec.js +5 -1
  21. package/build/__tests__/komaci-template-module.fixtures.spec.js +2 -1
  22. package/build/componentAstProcessing.d.ts +34 -0
  23. package/build/componentAstProcessing.js +105 -0
  24. package/build/compositionAstGeneration.d.ts +76 -0
  25. package/build/compositionAstGeneration.js +299 -0
  26. package/build/functionAstGeneration.d.ts +81 -0
  27. package/build/functionAstGeneration.js +337 -0
  28. package/build/genericAstGeneration.d.ts +107 -0
  29. package/build/genericAstGeneration.js +600 -0
  30. package/build/index.d.ts +6 -0
  31. package/build/index.js +85 -88
  32. package/build/types.d.ts +13 -2
  33. package/build/types.js +69 -1
  34. package/package.json +4 -4
  35. package/build/__tests__/modGenScript.spec.d.ts +0 -2
  36. package/build/__tests__/modGenScript.spec.js +0 -110
  37. package/build/__tests__/modGenTemplate.spec.d.ts +0 -2
  38. package/build/__tests__/modGenTemplate.spec.js +0 -196
  39. package/build/__tests__/shared.spec.d.ts +0 -2
  40. package/build/__tests__/shared.spec.js +0 -62
  41. package/build/__tests__/templateStrings.spec.d.ts +0 -2
  42. package/build/__tests__/templateStrings.spec.js +0 -130
  43. package/build/modGenScript.d.ts +0 -38
  44. package/build/modGenScript.js +0 -1027
  45. package/build/modGenTemplate.d.ts +0 -37
  46. package/build/modGenTemplate.js +0 -402
  47. package/build/shared.d.ts +0 -170
  48. package/build/shared.js +0 -588
@@ -0,0 +1,600 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.exportNamedDeclarationForDynamicImport = exports.addUndefinedDefaultExport = exports.propertyToExpression = exports.functionToExpression = exports.bindingToExpression = exports.primitiveToExpression = exports.valueToExpression = exports.processWireFunctionType = exports.processErrorFunction = exports.addImportStatements = exports.generateResolvableModule = void 0;
27
+ const common_shared_1 = require("@komaci/common-shared");
28
+ const static_analyzer_1 = require("@komaci/static-analyzer");
29
+ const t = __importStar(require("@babel/types"));
30
+ const compositionAstGeneration_1 = require("./compositionAstGeneration");
31
+ const componentAstProcessing_1 = require("./componentAstProcessing");
32
+ const types_1 = require("./types");
33
+ const functionAstGeneration_1 = require("./functionAstGeneration");
34
+ const CONTEXT_MAPPING = {
35
+ cpr: 'CurrentPageReference',
36
+ };
37
+ /**
38
+ * Compose a resolvable module for a component. There are three types of outputted resolvable modules
39
+ * - A resolvable module built from a component with ONLY a template
40
+ * - A resolvable module built from a component with ONLY a js file
41
+ * - A resolvable module that has both a template a js file
42
+ *
43
+ * Currently we only support JS and template files that match the names of components
44
+ *
45
+ * @param input Generator input
46
+ * @param scriptKomaciDoc The js komaci doc if it exists
47
+ * @param templateKomaciDoc The tempalte komaci doc if it exists
48
+ * @param source string pointing to the source of the script doc if it exists
49
+ * @returns The babel AST for the generated resolvable module
50
+ */
51
+ function generateResolvableModule(input, scriptKomaciDoc, templateKomaciDoc, source) {
52
+ const moduleMetadata = (0, common_shared_1.initModuleMetadataObject)();
53
+ let componentDefaultAdgIndex;
54
+ const hasScriptKomaciDoc = scriptKomaciDoc && Object.keys(scriptKomaciDoc).length !== 0;
55
+ const hasTemplateKomaciDoc = templateKomaciDoc && Object.keys(templateKomaciDoc).length !== 0;
56
+ const combinedModule = scriptKomaciDoc !== undefined && templateKomaciDoc !== undefined;
57
+ const isBundle = input.moduleInfo.type === 'bundle';
58
+ // start of metadata collection
59
+ if (scriptKomaciDoc) {
60
+ (0, common_shared_1.initializeImportMetdataFromKomaciDocument)(scriptKomaciDoc, moduleMetadata);
61
+ let ast;
62
+ if (source) {
63
+ ast = (0, common_shared_1.generateAstFromSrcCode)(source);
64
+ (0, common_shared_1.collectImportMetadataFromAst)(ast, moduleMetadata);
65
+ }
66
+ componentDefaultAdgIndex = scriptKomaciDoc.exports?.default?.value;
67
+ scriptKomaciDoc.adgs?.forEach((_, index) => (0, common_shared_1.initalizeAdgMetadata)(index, scriptKomaciDoc, moduleMetadata, componentDefaultAdgIndex === index && ast !== undefined, isBundle));
68
+ (0, common_shared_1.mapExportNamesToAdgs)(scriptKomaciDoc.exports, moduleMetadata);
69
+ if (ast && componentDefaultAdgIndex !== undefined) {
70
+ const { getters, templateStrings } = (0, common_shared_1.getPropertyMetadataFromAst)(ast);
71
+ const moduleContext = {
72
+ astContext: (0, common_shared_1.getAstContextObject)(ast),
73
+ isExternal: (0, common_shared_1.isExternalModule)(input.moduleInfo.namespace),
74
+ };
75
+ (0, componentAstProcessing_1.processGetters)(componentDefaultAdgIndex, moduleContext, moduleMetadata, getters);
76
+ (0, componentAstProcessing_1.processTemplateStrings)(componentDefaultAdgIndex, moduleContext, moduleMetadata, templateStrings);
77
+ }
78
+ }
79
+ if (hasTemplateKomaciDoc) {
80
+ componentDefaultAdgIndex = (0, common_shared_1.reconcileDefaultAdg)(componentDefaultAdgIndex, moduleMetadata);
81
+ (0, common_shared_1.initializeImportMetdataFromKomaciDocument)(templateKomaciDoc, moduleMetadata, true);
82
+ (0, common_shared_1.addTemplateUsageForDefaultAdg)(templateKomaciDoc, componentDefaultAdgIndex, moduleMetadata);
83
+ if (isBundle && !hasScriptKomaciDoc) {
84
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
85
+ (0, common_shared_1.upliftFakePropsFromTemplate)(moduleMetadata.adgs.get(componentDefaultAdgIndex));
86
+ }
87
+ }
88
+ // for script only docs we assume there there is still a html file around so we build the import to reference that html
89
+ if (!isBundle && hasScriptKomaciDoc && !hasTemplateKomaciDoc) {
90
+ const newImport = (0, common_shared_1.composeImportMetadata)('default', `@salesforce/komaci/${input.moduleInfo.namespace}__${input.moduleInfo.name}__${input.moduleInfo.name}.html`, true, common_shared_1.NO_KOMACI_DOC_REF, moduleMetadata, common_shared_1.IdKeys.DEFAULT_COMP);
91
+ newImport.usedInPriming = true;
92
+ newImport.isFromSupportedLibrary = true;
93
+ newImport.generatorAlias = 'comp1';
94
+ }
95
+ // all metadata collected at this point, time to start building ast
96
+ const statements = [];
97
+ const program = t.program(statements);
98
+ const file = t.file(program);
99
+ addImportStatements(moduleMetadata, statements, {
100
+ calledFromGenerateCombinedModule: combinedModule,
101
+ });
102
+ // template only resolvable modules are composed completely differently (for now)
103
+ if (!combinedModule && hasTemplateKomaciDoc) {
104
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
105
+ const adg = moduleMetadata.adgs.get(componentDefaultAdgIndex);
106
+ const compositionsArray = (0, compositionAstGeneration_1.compositionsToArrayExpression)(moduleMetadata, templateKomaciDoc.compositions) || t.arrayExpression([]);
107
+ // Create default export of the main template function.
108
+ // e.g. `export default function (fct, ctx) {...}`
109
+ const params = [types_1.ID.FACTORY, types_1.ID.CONTEXT];
110
+ const compositionFunction = [];
111
+ const body = t.blockStatement(compositionFunction);
112
+ // Destructuring of factory functions.
113
+ const fctFuncs = (0, functionAstGeneration_1.getFactoryFuncDeclaration)(adg.requiredCompositionFactoryFunctions);
114
+ if (fctFuncs) {
115
+ compositionFunction.push(fctFuncs);
116
+ }
117
+ // Return the array of composition expressions.
118
+ compositionFunction.push(t.returnStatement(compositionsArray));
119
+ statements.push(t.exportDefaultDeclaration(t.functionDeclaration(null, params, body)));
120
+ }
121
+ else {
122
+ // uplift local functions from default exported adg
123
+ if (componentDefaultAdgIndex !== undefined) {
124
+ const defaultAdg = moduleMetadata.adgs.get(componentDefaultAdgIndex);
125
+ defaultAdg?.functions.forEach((func) => {
126
+ if (func.type === common_shared_1.FunctionTypes.GETTER_FUNCTION ||
127
+ func.type === common_shared_1.FunctionTypes.TEMPLATE_STRING) {
128
+ const hoistedFunction = (0, functionAstGeneration_1.hoistLocalFunction)(func, moduleMetadata.importsByName);
129
+ if (hoistedFunction) {
130
+ statements.push(hoistedFunction);
131
+ }
132
+ }
133
+ });
134
+ }
135
+ else {
136
+ statements.push(addUndefinedDefaultExport());
137
+ }
138
+ for (const adg of moduleMetadata.adgs.values()) {
139
+ statements.push((0, functionAstGeneration_1.composeAdgFunction)(adg, moduleMetadata));
140
+ }
141
+ for (const [exportName, adg] of Object.entries(moduleMetadata.exports)) {
142
+ statements.push((0, functionAstGeneration_1.addExportStatement)(adg.defaultGeneratedName, exportName));
143
+ }
144
+ if (input.moduleInfo.type === 'bundle') {
145
+ statements.push(exportNamedDeclarationForDynamicImport(input.moduleInfo.name, input.moduleInfo.namespace, input.options?.targetModule));
146
+ }
147
+ }
148
+ return file;
149
+ }
150
+ exports.generateResolvableModule = generateResolvableModule;
151
+ /**
152
+ * Adds a babel import decleration to the AST for each Komaci import
153
+ *
154
+ * Note: While this method does not return anything, it does modify the input Statement array.
155
+ *
156
+ * @param {ModuleMetadata} moduleMetadata metadata about the lwc module we are building a resolvable module for
157
+ * @param {Statement[]} statements Array of Statement to be modified by this method for this program
158
+ * @param {{ calledFromGenerateCombinedModule: boolean }} options flag to distinguish whether we have been called
159
+ * to generate a combined module or not.
160
+ */
161
+ function addImportStatements(moduleMetadata, statements, options) {
162
+ if (moduleMetadata.importsByName.size > 0) {
163
+ const imports = Array.from(moduleMetadata.importsByName.values())
164
+ .sort((a, b) => {
165
+ if (a.resourceName < b.resourceName) {
166
+ return -1;
167
+ }
168
+ else if (a.resourceName > b.resourceName) {
169
+ return 1;
170
+ }
171
+ else {
172
+ return 0;
173
+ }
174
+ })
175
+ .filter((value) => value.isFromInternalNamespace && value.usedInPriming);
176
+ let i = 0;
177
+ while (i < imports.length) {
178
+ const specifiers = [];
179
+ let resourceName = imports[i].resourceName;
180
+ while (i < imports.length && imports[i].resourceName === resourceName) {
181
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
182
+ const localName = t.identifier(imports[i].generatorAlias);
183
+ let specifier;
184
+ const exportName = imports[i].name;
185
+ if (exportName === 'default') {
186
+ // e.g. `import i1 from "@salesforce/user/Id";`
187
+ specifier = t.importDefaultSpecifier(localName);
188
+ specifiers.unshift(specifier);
189
+ }
190
+ else if (exportName === '*' &&
191
+ moduleMetadata.importsByNamespace.get(resourceName)?.names.size === 1) {
192
+ // e.g. `import i1 from "@salesforce/user/Id";`
193
+ specifier = t.importNamespaceSpecifier(localName);
194
+ specifiers.push(specifier);
195
+ }
196
+ else {
197
+ // e.g. `import { getRecord as i1 } from "lightning/uiRecordApi";`.
198
+ // `getRecord` is the exportName, `i1` is the localName
199
+ specifier = t.importSpecifier(localName, t.identifier(exportName));
200
+ specifiers.push(specifier);
201
+ }
202
+ i++;
203
+ }
204
+ if ((0, static_analyzer_1.isSupportedNamespace)(resourceName) && specifiers.length > 0) {
205
+ if (options.calledFromGenerateCombinedModule &&
206
+ resourceName.startsWith('@salesforce/komaci')) {
207
+ // @salesforce/komaci/c__foo__foo.js -> @salesforce/komaci/c__foo
208
+ const lastIndex = resourceName.lastIndexOf('__');
209
+ resourceName = resourceName.slice(0, lastIndex);
210
+ }
211
+ const resource = t.stringLiteral(resourceName);
212
+ const importDeclaration = t.importDeclaration(specifiers, resource);
213
+ statements.push(importDeclaration);
214
+ }
215
+ }
216
+ }
217
+ }
218
+ exports.addImportStatements = addImportStatements;
219
+ /**
220
+ * Make ast statements for the details about an error we received
221
+ * @param adgFunc The error function metadata
222
+ * @param moduleMetadata metadata about the module as whole
223
+ * @returns ast statemenets representing config for this function node
224
+ */
225
+ function processErrorFunction(adgFunc, moduleMetadata) {
226
+ const funcObjProps = [];
227
+ const t_value = t.stringLiteral(types_1.ERROR_FUNCTION);
228
+ const configObjExpr = valueToExpression(adgFunc.input[0], moduleMetadata);
229
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_TYPE, t_value), t.objectProperty(types_1.ID.FUNC_CONFIG, configObjExpr));
230
+ return funcObjProps;
231
+ }
232
+ exports.processErrorFunction = processErrorFunction;
233
+ /**
234
+ * Function to generate the object property array for a wire function node type.
235
+ *
236
+ * NOTE: if the obj representing the function is from an unsupported namespace, and it
237
+ * is for a wire function, then leave out the function node from the generated resolvable
238
+ * module, by returning undefined.
239
+ * @param {ImportInfo} importInfo import information against which to check the wire function's validity
240
+ * @param {GeneratorState} generatorState the current state of the esm generator
241
+ * @param {FunctionType} adgFunc a wire function from the adg functions array.
242
+ * @returns {ObjectProperty[]} an representation of the wire function node as array of ObjectProperty
243
+ */
244
+ function processWireFunctionType(adgFunc, moduleMetadata) {
245
+ // Validate and set function type, e.g. `t: "WireFunction"`
246
+ if (adgFunc.type !== common_shared_1.FunctionTypes.WIRE_FUNCTION &&
247
+ adgFunc.type !== common_shared_1.FunctionTypes.PRIMING_FUNCTION) {
248
+ throw new Error(common_shared_1.ERROR_PREFIX + 'ADG function has invalid type');
249
+ }
250
+ const adapterImport = moduleMetadata.importsByName.get(adgFunc.importReference.functionName);
251
+ if (adapterImport) {
252
+ const funcObjProps = [];
253
+ // if the obj representing the function is from an unsupported namespace, and it is for a wire function,
254
+ // then leave out the function node form the generated resolvable module, by returning undefined.
255
+ const resourceName = adapterImport.resourceName;
256
+ const exportName = adapterImport.name;
257
+ if (!exportName ||
258
+ !(0, static_analyzer_1.isSupportedNamespace)(resourceName) ||
259
+ (adgFunc.type === common_shared_1.FunctionTypes.WIRE_FUNCTION &&
260
+ !(0, common_shared_1.isSupportedWireAdapter)(resourceName, exportName))) {
261
+ return undefined;
262
+ }
263
+ if (adgFunc.type === common_shared_1.FunctionTypes.PRIMING_FUNCTION) {
264
+ // Add props for imports relating to this priming adapter.
265
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_ID, t.identifier(adapterImport.generatorAlias)), t.objectProperty(types_1.ID.FUNC_NAME, t.stringLiteral(adgFunc.importReference.functionName)));
266
+ if (adgFunc.importReference.batchingName &&
267
+ moduleMetadata.importsByName.has(adgFunc.importReference.batchingName)) {
268
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
269
+ const batchImport = moduleMetadata.importsByName.get(adgFunc.importReference.batchingName);
270
+ funcObjProps.push(t.objectProperty(types_1.ID.BATCH_FUNC_ID, t.identifier(batchImport.generatorAlias)), t.objectProperty(types_1.ID.BATCH_FUNC_NAME, t.stringLiteral(adgFunc.importReference.batchingName)));
271
+ }
272
+ if (adgFunc.importReference.reducer &&
273
+ moduleMetadata.importsByName.has(adgFunc.importReference.reducer)) {
274
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
275
+ const reducerImport = moduleMetadata.importsByName.get(adgFunc.importReference.reducer);
276
+ funcObjProps.push(t.objectProperty(types_1.ID.REDUCER_FUNC_ID, t.identifier(reducerImport.generatorAlias)));
277
+ }
278
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_TYPE, t.stringLiteral(types_1.PRIMING_FUNCTION)));
279
+ }
280
+ else {
281
+ // Traditional wire adapter.
282
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_ID, t.identifier(adapterImport.generatorAlias)), t.objectProperty(types_1.ID.FUNC_NAME, t.stringLiteral(getWireName(resourceName, exportName))), t.objectProperty(types_1.ID.FUNC_TYPE, t.stringLiteral(types_1.WIRE_FUNCTION)));
283
+ // Check if the export name matches one of the supported context wires. If so we set
284
+ // wire type. e.g. `wt: "cpr"`
285
+ if (isSupportedContextWire(exportName)) {
286
+ const contextWireName = Object.keys(CONTEXT_MAPPING).find((key) => CONTEXT_MAPPING[key] === exportName);
287
+ if (contextWireName) {
288
+ funcObjProps.push(t.objectProperty(types_1.ID.WIRE_TYPE, t.stringLiteral(contextWireName)));
289
+ }
290
+ }
291
+ else if (isApexWire(resourceName)) {
292
+ funcObjProps.push(t.objectProperty(types_1.ID.WIRE_TYPE, t.stringLiteral('apex')));
293
+ }
294
+ }
295
+ // Construct function to return config object and list of input properties.
296
+ let configObjExpr;
297
+ const inputProps = new Set();
298
+ if (adgFunc.input && adgFunc.input.length > 0) {
299
+ if (adgFunc.input.length !== 1 || adgFunc.input[0].type !== 'ObjectValue') {
300
+ // Only valid input according to Wire Adapter Protocol.
301
+ throw new Error(common_shared_1.ERROR_PREFIX + 'WireFunction has invalid input');
302
+ }
303
+ const inputObject = adgFunc.input[0];
304
+ configObjExpr = t.objectExpression([]);
305
+ configObjExpr = valueToExpression(inputObject, moduleMetadata); // wireconfig import usage
306
+ // Create list of property names which are inputs into the function.
307
+ for (const propValue of Object.values(inputObject.value)) {
308
+ // NOTE: LWC doesn't allow for property references to be nested in
309
+ // objects or arrays, so only need to check the top-level props.
310
+ if (propValue.type === 'PropertyReference') {
311
+ inputProps.add(propValue.value.split('/')[0]);
312
+ }
313
+ }
314
+ }
315
+ else {
316
+ // Matches LWC compiler behavior which always pass an object into a wire's
317
+ // update() method. Even if original source doesn't provide config.
318
+ configObjExpr = t.objectExpression([]);
319
+ }
320
+ // e.g. `c: ctx => ({ recordId: "001RM000004UZqLYAW" })`
321
+ const configFunc = t.arrowFunctionExpression([types_1.ID.CONTEXT], configObjExpr);
322
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_CONFIG, configFunc));
323
+ // e.g. in: ['recordId', 'fields']
324
+ if (inputProps.size) {
325
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_INPUT, t.arrayExpression(Array.from(inputProps).map((v) => t.stringLiteral(v)))));
326
+ }
327
+ return funcObjProps;
328
+ }
329
+ }
330
+ exports.processWireFunctionType = processWireFunctionType;
331
+ /**
332
+ * Determines whether an export name matches one of the supported context wires
333
+ * @param {string | undefined} exportName the exportName of an import statement
334
+ * @returns {boolean} boolean true if the the export name matches a supported context wire
335
+ */
336
+ function isSupportedContextWire(exportName) {
337
+ return (exportName !== undefined && Object.values(CONTEXT_MAPPING).includes(exportName));
338
+ }
339
+ /**
340
+ * Determines whether the resourceName of an import statement is that of an Apex wire
341
+ * @param {string | undefined} resourceName a string representing the resource name (ex: '@salesforce/apex/myApexwire')
342
+ * @returns {boolean} true if the resource name represent that of an Apex wire, false otherwise
343
+ */
344
+ function isApexWire(resourceName) {
345
+ return !!(resourceName && resourceName.startsWith('@salesforce/apex/'));
346
+ }
347
+ /**
348
+ * Retrieves the name of an Apex wire
349
+ * @param {string} resourceName a string representing the resource name (ex: '@salesforce/apex/ContactController.getContactList')
350
+ * @param {string} exportName a string representing the name of the export (ex: `awire` in `import awire from '@salesforce/apex/awire'`)
351
+ * @returns {string} the Apex wire name, as a string
352
+ */
353
+ function getWireName(resourceName, exportName) {
354
+ if (isApexWire(resourceName)) {
355
+ // eg. @salesforce/apex/ContactController.getContactList -> ContactController.getContactList
356
+ return resourceName.substring('@salesforce/apex/'.length);
357
+ }
358
+ return exportName;
359
+ }
360
+ /**
361
+ * Convert any possible value within a Komaci ADG to a babel expression.
362
+ * @param komaciValue the komaci value
363
+ * @param moduleMetadata the module meta data object
364
+ * @returns a babel expression for the komaci value.
365
+ */
366
+ function valueToExpression(komaciValue, moduleMetadata) {
367
+ let newExpression;
368
+ switch (komaciValue.type) {
369
+ case 'PrimitiveValue':
370
+ newExpression = primitiveToExpression(komaciValue);
371
+ break;
372
+ case 'ImportReference': {
373
+ const importIndexReference = moduleMetadata.importIndexReference.get(komaciValue.value);
374
+ if (importIndexReference) {
375
+ const importMetadata = moduleMetadata.importsByName.get(importIndexReference);
376
+ newExpression =
377
+ importMetadata?.isFromInternalNamespace &&
378
+ importMetadata?.isFromSupportedLibrary &&
379
+ importMetadata.generatorAlias
380
+ ? t.identifier(importMetadata.generatorAlias)
381
+ : t.identifier(types_1.UNRESOLVED);
382
+ }
383
+ else {
384
+ newExpression = t.identifier(types_1.UNRESOLVED);
385
+ }
386
+ if (newExpression?.name !== types_1.UNRESOLVED && komaciValue.namespacedMember) {
387
+ newExpression = t.memberExpression(newExpression, t.identifier(komaciValue.namespacedMember));
388
+ }
389
+ break;
390
+ }
391
+ case 'PropertyReference': {
392
+ return bindingToExpression(komaciValue);
393
+ }
394
+ case 'Unresolved':
395
+ newExpression = types_1.ID.UNRESOLVED_VALUE;
396
+ break;
397
+ case 'ArrayValue': {
398
+ const elements = [];
399
+ komaciValue.value.forEach((element) => {
400
+ elements.push(valueToExpression(element, moduleMetadata));
401
+ });
402
+ newExpression = t.arrayExpression(elements);
403
+ break;
404
+ }
405
+ case 'ObjectValue': {
406
+ const objProps = [];
407
+ for (const [propName, propValue] of Object.entries(komaciValue.value)) {
408
+ objProps.push(t.objectProperty(t.stringLiteral(propName), valueToExpression(propValue, moduleMetadata)));
409
+ }
410
+ newExpression = t.objectExpression(objProps);
411
+ break;
412
+ }
413
+ }
414
+ if (!newExpression) {
415
+ throw new Error(`${common_shared_1.ERROR_PREFIX}: Unrecognized value type`);
416
+ }
417
+ return newExpression;
418
+ }
419
+ exports.valueToExpression = valueToExpression;
420
+ /**
421
+ * Convert a Komaci primitive value to babel expression.
422
+ * @param primitive a primitve value
423
+ * @returns an expression that represents the primitive value.
424
+ */
425
+ function primitiveToExpression(primitive) {
426
+ switch (typeof primitive.value) {
427
+ case 'number':
428
+ return t.numericLiteral(primitive.value);
429
+ case 'string':
430
+ return t.stringLiteral(primitive.value);
431
+ case 'boolean':
432
+ return t.booleanLiteral(primitive.value);
433
+ case 'undefined':
434
+ return types_1.ID.UNDEFINED;
435
+ default:
436
+ return t.nullLiteral();
437
+ }
438
+ }
439
+ exports.primitiveToExpression = primitiveToExpression;
440
+ /**
441
+ * Convert binding (or PropertyReference) to a babel expr (e.g. record.value?.Id).
442
+ * @param binding The binding object
443
+ * @param iterationContext If this binding is inside an iteration we need the contextual details about the iteration to build the proper expression
444
+ * @param parseRootOnly There are some cases where we only care about the first piece of the binding. in the example above we might need to only check `record` instead of `record.value?.Id`
445
+ * @returns A composed member expression
446
+ */
447
+ function bindingToExpression(binding, iterationContext, parseRootOnly = false) {
448
+ if (!binding.value.length) {
449
+ if (binding.type === 'Binding') {
450
+ throw new Error(common_shared_1.ERROR_PREFIX + 'encountered empty binding');
451
+ }
452
+ throw new Error(common_shared_1.ERROR_PREFIX + 'encountered empty property reference');
453
+ }
454
+ let segments = binding.value.split('/'); // segments[0] === propertyName
455
+ if (parseRootOnly) {
456
+ segments = [segments[0]];
457
+ }
458
+ let chainingStartIdx = 2;
459
+ let iteratorBinding = false;
460
+ // Am I in the context of an iteration?
461
+ if (iterationContext && iterationContext.includes(segments[0])) {
462
+ // Referencing property of an iteration
463
+ iteratorBinding = true; // flag to distinguish whether we are in the context of an iteration
464
+ chainingStartIdx = 1;
465
+ }
466
+ else {
467
+ chainingStartIdx = 2;
468
+ segments.unshift(common_shared_1.CONTEXT, common_shared_1.PROPS); // Referencing property in context, so prepend ctx.props
469
+ }
470
+ // Build member expression w/ optional chaining to prevent runtime TypeError.
471
+ // If we are in the context of an iterator binding, we must prepend the user variable prefix
472
+ let expr = iteratorBinding
473
+ ? t.identifier(types_1.USER_VARIABLE_PREFIX + segments[0])
474
+ : t.identifier(segments[0]);
475
+ for (let i = 1; i < segments.length; ++i) {
476
+ expr = t.optionalMemberExpression(expr, t.identifier(segments[i]), false, i > chainingStartIdx);
477
+ }
478
+ return expr;
479
+ }
480
+ exports.bindingToExpression = bindingToExpression;
481
+ /**
482
+ * Convert a single Komaci function to an object expression in the shape of a
483
+ * FunctionDefinition as defined in Resolver API.
484
+ * @param {GeneratorState} generatorState the current esm generator state
485
+ * @param {FunctionType} adgFunc a function from the adg functions arrray.
486
+ * @returns {Expression} a babel Expression if propertly processed or undefined.
487
+ */
488
+ function functionToExpression(moduleMetadata, adgFunc) {
489
+ if (adgFunc.type === common_shared_1.FunctionTypes.GETTER_FUNCTION) {
490
+ const getterFuncObjPropArr = processLocalFunction(adgFunc, common_shared_1.GETTER_FUNCTION);
491
+ return t.objectExpression(getterFuncObjPropArr);
492
+ }
493
+ else if (adgFunc.type === common_shared_1.FunctionTypes.TEMPLATE_STRING) {
494
+ return t.objectExpression(processLocalFunction(adgFunc, common_shared_1.TEMPLATED_STRING_FUNCTION));
495
+ }
496
+ else if (adgFunc.type === common_shared_1.FunctionTypes.ERROR) {
497
+ return t.objectExpression(processErrorFunction(adgFunc, moduleMetadata));
498
+ }
499
+ else if (adgFunc.type === common_shared_1.FunctionTypes.WIRE_FUNCTION ||
500
+ adgFunc.type === common_shared_1.FunctionTypes.PRIMING_FUNCTION) {
501
+ const wireFunctionObjArr = processWireFunctionType(adgFunc, moduleMetadata);
502
+ if (wireFunctionObjArr) {
503
+ return t.objectExpression(wireFunctionObjArr);
504
+ }
505
+ }
506
+ return undefined;
507
+ }
508
+ exports.functionToExpression = functionToExpression;
509
+ /**
510
+ * Function to create the object property array for a local function
511
+ * @param {FunctionType} adgFunc a function from the adg functions array.
512
+ * @param {string} type The type of function. getter or templated string
513
+ * @returns {ObjectProperty[]} a babel object property array.
514
+ */
515
+ function processLocalFunction(hoistedFunc, type) {
516
+ const funcObjProps = [];
517
+ const f_reference = {
518
+ type: 'Identifier',
519
+ name: hoistedFunc.generatedName ? hoistedFunc.generatedName : types_1.UNRESOLVED,
520
+ leadingComments: null,
521
+ innerComments: null,
522
+ trailingComments: null,
523
+ start: null,
524
+ end: null,
525
+ loc: null,
526
+ };
527
+ const t_value = t.stringLiteral(type);
528
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_ID, f_reference), t.objectProperty(types_1.ID.FUNC_TYPE, t_value));
529
+ hoistedFunc.requiredProperties;
530
+ if (hoistedFunc.requiredProperties) {
531
+ const in_value = t.arrayExpression(hoistedFunc.requiredProperties.map((v) => t.stringLiteral(v)));
532
+ funcObjProps.push(t.objectProperty(types_1.ID.FUNC_INPUT, in_value));
533
+ }
534
+ return funcObjProps;
535
+ }
536
+ /**
537
+ * Convert a single Komaci property to an object expression in the shape of
538
+ * a PropertyDefinition as defined in Resolver API.
539
+ * @param {GeneratorState} generatorState the current state of esm-generator
540
+ * @param {Adg} adg the current ADG from which to seek out FunctionReferences
541
+ * @param {Propery} property the Komaci property to process
542
+ * @returns {Expression} the komaci property converted to an object Expression
543
+ */
544
+ function propertyToExpression(moduleMetadata, property) {
545
+ const objProps = [];
546
+ // Whether the prop is public or not, e.g. `a: true`.
547
+ objProps.push(t.objectProperty(types_1.ID.PROP_API, t.booleanLiteral(property.isPublic)));
548
+ if (property.inital) {
549
+ // initial value
550
+ // Initial value of the prop, e.g. `i: 5`.
551
+ objProps.push(t.objectProperty(types_1.ID.PROP_INIT, valueToExpression(property.inital, moduleMetadata)));
552
+ }
553
+ if (property.type === common_shared_1.PropertyTypes.GETTER ||
554
+ property.type === common_shared_1.PropertyTypes.WIRE ||
555
+ property.type === common_shared_1.PropertyTypes.TEMPLATE_STRING) {
556
+ // Index of function where this property receives input, e.g. `f: 0`.
557
+ const funcIdx = property.functionIndex;
558
+ if (funcIdx === common_shared_1.UNSUPPORTED_FUNCTION) {
559
+ objProps.push(t.objectProperty(types_1.ID.PROP_GETTER, types_1.ID.UNRESOLVED_VALUE));
560
+ }
561
+ else {
562
+ objProps.push(t.objectProperty(types_1.ID.PROP_FUNC, t.numericLiteral(funcIdx)));
563
+ }
564
+ }
565
+ return t.objectExpression(objProps);
566
+ }
567
+ exports.propertyToExpression = propertyToExpression;
568
+ /**
569
+ * Adds a default export to the program statements, if no default export that is derived from an AdgReference already exists
570
+ *
571
+ * @returns composed AST statement for undefined default export
572
+ */
573
+ function addUndefinedDefaultExport() {
574
+ return t.exportDefaultDeclaration(t.functionDeclaration(null, [], t.blockStatement([t.returnStatement(types_1.ID.UNDEFINED)])));
575
+ }
576
+ exports.addUndefinedDefaultExport = addUndefinedDefaultExport;
577
+ /**
578
+ * Adds the dynamic import of target module, but only for bundles (if moduleInfo.type === "bundle").
579
+ *
580
+ * Returns an export named declaration. The declaration is assigned an arrowFunctionExpression, which returns
581
+ * a dynamic import based on the moduleInfo namespace and name.
582
+ * @param moduleName The name of module we're making
583
+ * @param moduleNamespace the namespace for this given module
584
+ * @param targetModule name of the target module if it exists
585
+ * @returns ExportNamedDeclaration containing the statement of the dynamic import of the target module
586
+ */
587
+ function exportNamedDeclarationForDynamicImport(moduleName, moduleNamespace, targetModule) {
588
+ const IMPORT_TARGET = 'importTarget';
589
+ const FUNC_NAME_IMPORT = 'import';
590
+ const CONST_TYPE = 'const';
591
+ const moduleResourceName = targetModule || moduleNamespace + '/' + moduleName;
592
+ const returnStatement = t.returnStatement(t.callExpression(t.identifier(FUNC_NAME_IMPORT), [
593
+ t.stringLiteral(moduleResourceName),
594
+ ]));
595
+ return t.exportNamedDeclaration(t.variableDeclaration(CONST_TYPE, [
596
+ t.variableDeclarator(t.identifier(IMPORT_TARGET), t.arrowFunctionExpression([], t.blockStatement([returnStatement]))),
597
+ ]));
598
+ }
599
+ exports.exportNamedDeclarationForDynamicImport = exportNamedDeclarationForDynamicImport;
600
+ //# sourceMappingURL=genericAstGeneration.js.map
package/build/index.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import { GeneratorInput } from './types';
2
2
  export { GeneratorInput } from './types';
3
3
  export declare function generateKomaciModule(input: GeneratorInput): string;
4
+ /**
5
+ * Helper function to process and build the resolvable module based off the generator input and inital generator state.
6
+ * @param input the Generator input
7
+ * @returns the resolvable module.
8
+ */
9
+ export declare function processGeneratorInputAndState(input: GeneratorInput): string;
4
10
  //# sourceMappingURL=index.d.ts.map