@komaci/esm-generator 240.1.5 → 242.1.1

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