@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
@@ -35,6 +35,7 @@ function generateModuleSource(komaciHTMLDoc, komaciJSDoc, srcFileMap) {
35
35
  input.srcFileMap = srcFileMap;
36
36
  return (0, index_1.generateKomaciModule)(input);
37
37
  }
38
+ // eslint-disable-next-line jest/no-disabled-tests
38
39
  describe('fixtures', () => {
39
40
  // find all folder paths containing a file whose name ends in ".src"
40
41
  const fixtures = glob_1.default.sync(path_1.default.resolve(FIXTURES_DIR, '**/*.src'));
@@ -30,6 +30,7 @@ function generateModuleSource(komaciDoc, actualSrc) {
30
30
  }
31
31
  return (0, index_1.generateKomaciModule)(input);
32
32
  }
33
+ // eslint-disable-next-line jest/no-disabled-tests
33
34
  describe('fixtures', () => {
34
35
  const fixtures = glob_1.default.sync(path_1.default.resolve(FIXTURES_DIR, '**/*.json'));
35
36
  for (const caseEntry of fixtures) {
@@ -48,12 +49,14 @@ describe('fixtures', () => {
48
49
  const filePath = fixtureFilePath(fileName);
49
50
  fs_1.default.writeFileSync(filePath, content, { encoding: 'utf-8' });
50
51
  };
52
+ // if you need to test a specific case, uncomment out the if
53
+ // if (caseName === 'class-props') {
51
54
  it(`${caseName}`, () => {
52
55
  const src = readFixtureFile(INPUT_JSON_FILENAME);
53
56
  const komaciDoc = JSON.parse(src);
54
57
  const actualModuleSrc = generateModuleSource(komaciDoc, readFixtureFile('actual.js'));
55
58
  let expectedModuleSrc = readFixtureFile(EXPECTED_JS_FILENAME);
56
- if (expectedModuleSrc === null) {
59
+ if (expectedModuleSrc === undefined) {
57
60
  // write file if doesn't exist (ie new fixture)
58
61
  expectedModuleSrc = actualModuleSrc;
59
62
  writeFixtureFile(EXPECTED_JS_FILENAME, expectedModuleSrc);
@@ -61,6 +64,7 @@ describe('fixtures', () => {
61
64
  // check that the actual newly generated mod source matches expected
62
65
  expect(actualModuleSrc).toEqual(expectedModuleSrc);
63
66
  });
67
+ // }
64
68
  }
65
69
  });
66
70
  //# sourceMappingURL=komaci-script-module.fixtures.spec.js.map
@@ -22,7 +22,8 @@ function generateModuleSource(komaciDoc) {
22
22
  };
23
23
  return (0, index_1.generateKomaciModule)(input);
24
24
  }
25
- describe('fixtures', () => {
25
+ // eslint-disable-next-line jest/no-disabled-tests
26
+ describe('template only fixtures', () => {
26
27
  const fixtures = glob_1.default.sync(path_1.default.resolve(FIXTURES_DIR, '**/*.json'));
27
28
  for (const caseEntry of fixtures) {
28
29
  const caseFolder = path_1.default.dirname(caseEntry);
@@ -0,0 +1,34 @@
1
+ import * as t from '@babel/types';
2
+ import { GeneratorInput } from './types';
3
+ import { NodePath } from '@babel/core';
4
+ import { ModuleContext, ModuleMetadata } from '@komaci/common-shared';
5
+ /**
6
+ * Retrieve the file path for the js of a component
7
+ * @param generatorState GeneratorState containg the GeneratorInput, which in turn contains the JS raw source file
8
+ * @returns Returns raw source code as string for the js of a component if it exists in the srcFileMap
9
+ * Returns undefined if no JS source file (whose filename also matches the LWC module name) was included in the
10
+ * GeneratorState.GeneratorInput by lwc-platform, other calling code.
11
+ */
12
+ export declare function getComponentSrcJs(generatorInput: GeneratorInput): string | undefined;
13
+ /**
14
+ * AST is traversed to see if they contain getter functions that are not valid. For each getter that is valid, we will
15
+ * update contextual information about the class and pass back info about the valid getters.
16
+ *
17
+ * @param {ClassPropertyContexts} properties the Map of properties metadata, which tells whether a property is used by a wire functions
18
+ * @param {ModuleContext} moduleContext Contextual info about the module itself
19
+ * @param {ModuleLevelConsumption} moduleLevelConsumption Details about how things are consuming module level entities. NOTE: This is updated in here for import usage
20
+ * @param {t.File} ast The ast for the module
21
+ * @returns Information about valid getters to be added to the resolvable Module.
22
+ */
23
+ export declare function processGetters(adgIndex: number, moduleContext: ModuleContext, moduleMetadata: ModuleMetadata, getterMethodPaths: NodePath<t.ClassMethod>[]): void;
24
+ /**
25
+ * Validate what templates are good and then uplift the metadata about how they interact with other portions of the modules.
26
+ * i.e. import, property references, used in priming
27
+ * @param {ClassPropertyContexts} properties the Map of properties metadata, which tells whether a property is used by a wire functions
28
+ * @param {ModuleContext} moduleContext Contextual info about the module itself
29
+ * @param {ModuleLevelConsumption} moduleLevelConsumption Details about how things are consuming module level entities. NOTE: This is updated in here for import usage
30
+ * @param {Array<NodePath<t.ClassProperty>>} templateStrings The templates to validate
31
+ * @returns Information about valid templates to be added to the resolvable Module.
32
+ */
33
+ export declare function processTemplateStrings(adgIndex: number, moduleContext: ModuleContext, moduleMetadata: ModuleMetadata, templateStrings: Array<NodePath<t.ClassProperty>>): void;
34
+ //# sourceMappingURL=componentAstProcessing.d.ts.map
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processTemplateStrings = exports.processGetters = exports.getComponentSrcJs = void 0;
4
+ const static_analyzer_1 = require("@komaci/static-analyzer");
5
+ const common_shared_1 = require("@komaci/common-shared");
6
+ /**
7
+ * Retrieve the file path for the js of a component
8
+ * @param generatorState GeneratorState containg the GeneratorInput, which in turn contains the JS raw source file
9
+ * @returns Returns raw source code as string for the js of a component if it exists in the srcFileMap
10
+ * Returns undefined if no JS source file (whose filename also matches the LWC module name) was included in the
11
+ * GeneratorState.GeneratorInput by lwc-platform, other calling code.
12
+ */
13
+ function getComponentSrcJs(generatorInput) {
14
+ let sourceCode;
15
+ const moduleName = generatorInput.moduleInfo.name;
16
+ if (generatorInput.srcFileMap) {
17
+ const filename = Object.keys(generatorInput.srcFileMap).find((filename) => filename.endsWith('.js') && filename.startsWith(moduleName));
18
+ if (filename) {
19
+ sourceCode = generatorInput.srcFileMap[filename];
20
+ }
21
+ }
22
+ return sourceCode;
23
+ }
24
+ exports.getComponentSrcJs = getComponentSrcJs;
25
+ /**
26
+ * AST is traversed to see if they contain getter functions that are not valid. For each getter that is valid, we will
27
+ * update contextual information about the class and pass back info about the valid getters.
28
+ *
29
+ * @param {ClassPropertyContexts} properties the Map of properties metadata, which tells whether a property is used by a wire functions
30
+ * @param {ModuleContext} moduleContext Contextual info about the module itself
31
+ * @param {ModuleLevelConsumption} moduleLevelConsumption Details about how things are consuming module level entities. NOTE: This is updated in here for import usage
32
+ * @param {t.File} ast The ast for the module
33
+ * @returns Information about valid getters to be added to the resolvable Module.
34
+ */
35
+ function processGetters(adgIndex, moduleContext, moduleMetadata, getterMethodPaths) {
36
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
37
+ const adg = moduleMetadata.adgs.get(adgIndex);
38
+ getterMethodPaths
39
+ // map changes the item at each index to be an instance of ValidGetterContext
40
+ .forEach((getter, index) => {
41
+ const isGetterValid = (0, static_analyzer_1.validateGetter)(getter, adgIndex, moduleMetadata, moduleContext, false);
42
+ const getterName = (0, common_shared_1.getClassMethodName)(getter);
43
+ if (isGetterValid) {
44
+ const { identifiers } = (0, common_shared_1.implicitConsumptionMetadata)(getter, adgIndex, moduleMetadata);
45
+ const property = adg.properties.get(getterName);
46
+ if (property) {
47
+ property.type = common_shared_1.PropertyTypes.GETTER;
48
+ const functionMeta = {
49
+ type: common_shared_1.FunctionTypes.GETTER_FUNCTION,
50
+ componentAstNode: getter,
51
+ requiredProperties: identifiers,
52
+ generatedName: `g${index}`,
53
+ };
54
+ const functionIndex = adg.functions.push(functionMeta) - 1;
55
+ property.functionIndex = functionIndex;
56
+ property.inital = undefined;
57
+ }
58
+ (0, common_shared_1.updatePropertyUsage)(getterName, identifiers, adg.properties, common_shared_1.PropertyTypes.GETTER);
59
+ }
60
+ else {
61
+ const property = adg.properties.get(getterName);
62
+ if (property) {
63
+ property.type = common_shared_1.PropertyTypes.GETTER;
64
+ property.functionIndex = common_shared_1.UNSUPPORTED_FUNCTION;
65
+ }
66
+ }
67
+ });
68
+ }
69
+ exports.processGetters = processGetters;
70
+ /**
71
+ * Validate what templates are good and then uplift the metadata about how they interact with other portions of the modules.
72
+ * i.e. import, property references, used in priming
73
+ * @param {ClassPropertyContexts} properties the Map of properties metadata, which tells whether a property is used by a wire functions
74
+ * @param {ModuleContext} moduleContext Contextual info about the module itself
75
+ * @param {ModuleLevelConsumption} moduleLevelConsumption Details about how things are consuming module level entities. NOTE: This is updated in here for import usage
76
+ * @param {Array<NodePath<t.ClassProperty>>} templateStrings The templates to validate
77
+ * @returns Information about valid templates to be added to the resolvable Module.
78
+ */
79
+ function processTemplateStrings(adgIndex, moduleContext, moduleMetadata, templateStrings) {
80
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
81
+ const adg = moduleMetadata.adgs.get(adgIndex);
82
+ return templateStrings.forEach((template, index) => {
83
+ const isTemplateValid = (0, static_analyzer_1.validateTemplateString)(template, adgIndex, moduleMetadata, moduleContext, false);
84
+ const name = (0, common_shared_1.getFromIdentifierOrStringLiteral)(template.node.key);
85
+ const property = adg.properties.get(name);
86
+ if (isTemplateValid) {
87
+ const { identifiers } = (0, common_shared_1.implicitConsumptionMetadata)(template, adgIndex, moduleMetadata);
88
+ if (property) {
89
+ property.type = common_shared_1.PropertyTypes.TEMPLATE_STRING;
90
+ const functionMeta = {
91
+ type: common_shared_1.FunctionTypes.TEMPLATE_STRING,
92
+ componentAstNode: template,
93
+ requiredProperties: identifiers,
94
+ generatedName: `t${index}`,
95
+ };
96
+ const functionIndex = adg.functions.push(functionMeta) - 1;
97
+ property.functionIndex = functionIndex;
98
+ property.inital = undefined;
99
+ }
100
+ (0, common_shared_1.updatePropertyUsage)(name, identifiers, adg.properties, common_shared_1.PropertyTypes.TEMPLATE_STRING);
101
+ }
102
+ });
103
+ }
104
+ exports.processTemplateStrings = processTemplateStrings;
105
+ //# sourceMappingURL=componentAstProcessing.js.map
@@ -0,0 +1,76 @@
1
+ import { Composition, Container, ComposedAdg, Iteration, Slot, Image } from '@komaci/types';
2
+ import { ModuleMetadata } from '@komaci/common-shared';
3
+ import * as t from '@babel/types';
4
+ /**
5
+ * Convert an array of Komaci Compositions into a babel array of expressions.
6
+ * This is used for both the top-level compositions in the Komaci Doc, as well
7
+ * as their nested child compositions.
8
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
9
+ * @param {Composition[]} compositions an array of Compositions from a Template JS
10
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
11
+ * @returns {ArrayExpression | undefined} an ArrayExpression representing the passed in Composition array, or undefined
12
+ * if no compositions were passed in
13
+ */
14
+ export declare function compositionsToArrayExpression(moduleMetadata: ModuleMetadata, compositions?: Composition[], iterationContext?: string[]): t.ArrayExpression | undefined;
15
+ /**
16
+ * Convert any of the Komaci composition types into a babel expression, to be included in the generated module.
17
+ * NOTE: For instances where a composition has an isActive coditional, the module will be using the u function provided by the fct factory object to
18
+ * to check for an unresolved value. This function can be overridden, otherwise the default implementaitno will be used. https://salesforce.quip.com/XY4WAbfaLR5E
19
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
20
+ * @param {Composition} composition the Composition to covert
21
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
22
+ * @returns {Expression | ArrayExpression} the babel expression (Expression | ArrayExpression) to which the Composition was converted
23
+ */
24
+ export declare function compositionToExpression(moduleMetadata: ModuleMetadata, composition: Composition, iterationContext?: string[]): t.Expression | t.ArrayExpression;
25
+ /**
26
+ * Converts a Komaci container into a babel expression. If the container doesn't
27
+ * impact data flow, then an ArrayExpression is returned for its children.
28
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
29
+ * @param {Container} container the Komaci container (i.e. <div> tag)
30
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
31
+ * @returns {Expression | ArrayExpression} The babel Expression or ArrayExpression converted from the input Container
32
+ */
33
+ export declare function containerToExpression(moduleMetadata: ModuleMetadata, container: Container, iterationContext?: string[]): t.Expression | t.ArrayExpression;
34
+ /**
35
+ * Converts a Komaci ComposedAdg (which references an Import) into a call to the Resolver API for a composed graph, `cg`.
36
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
37
+ * @param {ComposedAdg} composedAdg the ComposedAdg whose input.type is an `ImportReference`
38
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
39
+ * @returns {Expression} a babel Expression representing the composed graph (cg) resolver API call. Throws an Error if the
40
+ * composedAdg.input.type is not equal to 'ImportReference'
41
+ */
42
+ export declare function composedAdgToExpression(moduleMetadata: ModuleMetadata, composedAdg: ComposedAdg, iterationContext?: string[]): t.Expression;
43
+ /**
44
+ * Converts a Komaci Iteration into a call to Resolver API for an iteration, i.e `i`.
45
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
46
+ * @param {Iteration} iteration the Iteration from a template file
47
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
48
+ * @returns {Expression} the babel Expression that represents the call into the Resolver API for an iteration
49
+ */
50
+ export declare function iterationToExpression(moduleMetadata: ModuleMetadata, iteration: Iteration, iterationContext?: string[]): t.Expression;
51
+ /**
52
+ * Convert Komaci slot into call to Resolver API for a slot, `s`
53
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
54
+ * @param {Slot} slot The Slot to be converted into an expression
55
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
56
+ * @returns {Expression} the babel Expression representing the Slot call into the Resolver API
57
+ */
58
+ export declare function slotToExpression(moduleMetadata: ModuleMetadata, slot: Slot, iterationContext?: string[]): t.Expression;
59
+ /**
60
+ * Converts Komaci Image into prompt for the Resolver API to make an image priming call
61
+ * @param {GeneratorState} generatorState the current state of the esm generator
62
+ * @param {Image} image the Image node from the KomaciDocument
63
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
64
+ * @returns {Expression} the babel Expression representing the Image prompt into the Resolver API
65
+ */
66
+ export declare function imageToExpression(image: Image, iterationContext?: string[]): t.Expression;
67
+ /**
68
+ * Creates a babel configuration ObjectExpression for provided composition. This is the `CompositionConfig`
69
+ * from Resolver API in its babel ObjectExpression form.
70
+ * @param {ComposedAdg | Container | Slot} composition the Composition from which to create a configuration (as a ComposedAdg, Container, or Slot)
71
+ * @param {string} componentId the component indentifier, as a string
72
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
73
+ * @returns {ObjectExpression} the babel ObjectExpression representing the Resolver API CompositionConfig
74
+ */
75
+ export declare function getCompositionConfig(composition: ComposedAdg | Container | Slot, componentId?: string, iterationContext?: string[]): t.ObjectExpression;
76
+ //# sourceMappingURL=compositionAstGeneration.d.ts.map
@@ -0,0 +1,299 @@
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.getCompositionConfig = exports.imageToExpression = exports.slotToExpression = exports.iterationToExpression = exports.composedAdgToExpression = exports.containerToExpression = exports.compositionToExpression = exports.compositionsToArrayExpression = void 0;
27
+ const common_shared_1 = require("@komaci/common-shared");
28
+ const t = __importStar(require("@babel/types"));
29
+ const genericAstGeneration_1 = require("./genericAstGeneration");
30
+ const types_1 = require("./types");
31
+ /**
32
+ * Convert an array of Komaci Compositions into a babel array of expressions.
33
+ * This is used for both the top-level compositions in the Komaci Doc, as well
34
+ * as their nested child compositions.
35
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
36
+ * @param {Composition[]} compositions an array of Compositions from a Template JS
37
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
38
+ * @returns {ArrayExpression | undefined} an ArrayExpression representing the passed in Composition array, or undefined
39
+ * if no compositions were passed in
40
+ */
41
+ function compositionsToArrayExpression(moduleMetadata, compositions, iterationContext) {
42
+ if (!compositions) {
43
+ return undefined;
44
+ }
45
+ const elements = [];
46
+ compositions.forEach((composition) => {
47
+ const expr = compositionToExpression(moduleMetadata, composition, iterationContext);
48
+ if (expr) {
49
+ if (t.isArrayExpression(expr)) {
50
+ // Special case, such as the top-most container, where the container has
51
+ // no impact on resolution process. In which case we want to flatten
52
+ // the array to effectively remove the container from the generated mod.
53
+ expr.elements.forEach((element) => {
54
+ if (t.isExpression(element)) {
55
+ elements.push(element);
56
+ }
57
+ });
58
+ }
59
+ else {
60
+ elements.push(expr);
61
+ }
62
+ }
63
+ });
64
+ return t.arrayExpression(elements);
65
+ }
66
+ exports.compositionsToArrayExpression = compositionsToArrayExpression;
67
+ /**
68
+ * Convert any of the Komaci composition types into a babel expression, to be included in the generated module.
69
+ * NOTE: For instances where a composition has an isActive coditional, the module will be using the u function provided by the fct factory object to
70
+ * to check for an unresolved value. This function can be overridden, otherwise the default implementaitno will be used. https://salesforce.quip.com/XY4WAbfaLR5E
71
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
72
+ * @param {Composition} composition the Composition to covert
73
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
74
+ * @returns {Expression | ArrayExpression} the babel expression (Expression | ArrayExpression) to which the Composition was converted
75
+ */
76
+ function compositionToExpression(moduleMetadata, composition, iterationContext) {
77
+ let expression;
78
+ // Get the expression specific to each type of composition.
79
+ switch (composition.type) {
80
+ case 'Container':
81
+ expression = containerToExpression(moduleMetadata, composition, iterationContext);
82
+ break;
83
+ case 'ComposedAdg':
84
+ expression = composedAdgToExpression(moduleMetadata, composition, iterationContext);
85
+ break;
86
+ case 'Iteration':
87
+ expression = iterationToExpression(moduleMetadata, composition, iterationContext);
88
+ break;
89
+ case 'Slot':
90
+ expression = slotToExpression(moduleMetadata, composition, iterationContext);
91
+ break;
92
+ case 'Image':
93
+ expression = imageToExpression(composition, iterationContext);
94
+ break;
95
+ }
96
+ // If the composition has an isActive condition, then
97
+ // expression needs to be proceded by a conditional check.
98
+ if (composition.isActive) {
99
+ let conditionalTest = (0, genericAstGeneration_1.bindingToExpression)(composition.isActive.input, iterationContext);
100
+ if (composition.isActive.negate) {
101
+ conditionalTest = t.unaryExpression('!', conditionalTest);
102
+ }
103
+ const prop = (0, genericAstGeneration_1.bindingToExpression)(composition.isActive.input, iterationContext, true);
104
+ const unresolvedTest = t.callExpression(types_1.ID.UNRESOLVED_FUNC, [prop]);
105
+ const test = t.logicalExpression('||', unresolvedTest, conditionalTest);
106
+ expression = t.conditionalExpression(test, expression, types_1.ID.UNDEFINED);
107
+ }
108
+ return expression;
109
+ }
110
+ exports.compositionToExpression = compositionToExpression;
111
+ /**
112
+ * Converts a Komaci container into a babel expression. If the container doesn't
113
+ * impact data flow, then an ArrayExpression is returned for its children.
114
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
115
+ * @param {Container} container the Komaci container (i.e. <div> tag)
116
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
117
+ * @returns {Expression | ArrayExpression} The babel Expression or ArrayExpression converted from the input Container
118
+ */
119
+ function containerToExpression(moduleMetadata, container, iterationContext) {
120
+ const children = compositionsToArrayExpression(moduleMetadata, container.compositions, iterationContext) || t.arrayExpression([]);
121
+ // If key or slot is specified, then the container will need to be
122
+ // accounted for in the module via the element function.
123
+ if (container.key || container.slot) {
124
+ const params = [];
125
+ // arg1: Composition configuration.
126
+ params.push(getCompositionConfig(container, undefined, iterationContext));
127
+ // arg2: Context.
128
+ params.push(types_1.ID.CONTEXT);
129
+ // arg3: Array of expressions for each child.
130
+ params.push(children);
131
+ return t.callExpression(types_1.ID.ELEMENT_FUNC, params);
132
+ }
133
+ else {
134
+ // No key or slot, so only need to include it's children
135
+ // in the generated mod.
136
+ return children.elements.length === 1
137
+ ? children.elements[0]
138
+ : children;
139
+ }
140
+ }
141
+ exports.containerToExpression = containerToExpression;
142
+ /**
143
+ * Converts a Komaci ComposedAdg (which references an Import) into a call to the Resolver API for a composed graph, `cg`.
144
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
145
+ * @param {ComposedAdg} composedAdg the ComposedAdg whose input.type is an `ImportReference`
146
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
147
+ * @returns {Expression} a babel Expression representing the composed graph (cg) resolver API call. Throws an Error if the
148
+ * composedAdg.input.type is not equal to 'ImportReference'
149
+ */
150
+ function composedAdgToExpression(moduleMetadata, composedAdg, iterationContext) {
151
+ let componentId;
152
+ const params = [];
153
+ // arg1: Input source to the composed graph function.
154
+ if (composedAdg.input.type === 'ImportReference') {
155
+ const importName = moduleMetadata.importIndexReference.get('t-' + composedAdg.input.value);
156
+ const importInfo = importName
157
+ ? moduleMetadata.importsByName.get(importName)
158
+ : undefined;
159
+ if (importInfo) {
160
+ componentId = importInfo.componentId;
161
+ params.push(t.identifier(importInfo.generatorAlias));
162
+ }
163
+ }
164
+ else {
165
+ // Schema supports this, but downstream logic (e.g. analysis) doesn't (yet).
166
+ throw new Error(common_shared_1.ERROR_PREFIX + 'binding not yet supported for ComposedAdg input');
167
+ }
168
+ // arg2: Composition configuration.
169
+ params.push(getCompositionConfig(composedAdg, componentId, iterationContext));
170
+ // arg3: Context.
171
+ params.push(types_1.ID.CONTEXT);
172
+ // arg4: Array of expressions for each child.
173
+ const children = compositionsToArrayExpression(moduleMetadata, composedAdg.compositions, iterationContext);
174
+ if (children && children.elements.length) {
175
+ params.push(children);
176
+ }
177
+ return t.callExpression(types_1.ID.COMPOSED_GRAPH_FUNC, params);
178
+ }
179
+ exports.composedAdgToExpression = composedAdgToExpression;
180
+ /**
181
+ * Converts a Komaci Iteration into a call to Resolver API for an iteration, i.e `i`.
182
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
183
+ * @param {Iteration} iteration the Iteration from a template file
184
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
185
+ * @returns {Expression} the babel Expression that represents the call into the Resolver API for an iteration
186
+ */
187
+ function iterationToExpression(moduleMetadata, iteration, iterationContext = []) {
188
+ const params = [];
189
+ // arg1: Expression for the collection being iterated.
190
+ params.push((0, genericAstGeneration_1.bindingToExpression)(iteration.input, iterationContext));
191
+ // arg2: Context.
192
+ params.push(types_1.ID.CONTEXT);
193
+ // arg3: Function to return compositions inside the the iteration.
194
+ // Use context to understand which iterations contain the code being analyzed.
195
+ iterationContext.unshift(iteration.iterator);
196
+ const children = compositionsToArrayExpression(moduleMetadata, iteration.compositions, iterationContext) || t.arrayExpression([]);
197
+ iterationContext.shift();
198
+ // interation.iterator contains string variables like "i", "j", "k", or loop control
199
+ // variables must prepend user variable prefix "user_var_" to the variable when used
200
+ // in arrow function declaration, to prevent resolution issues
201
+ params.push(t.arrowFunctionExpression([t.identifier(types_1.USER_VARIABLE_PREFIX + iteration.iterator)], t.blockStatement([t.returnStatement(children)])));
202
+ return t.callExpression(types_1.ID.ITERATION_FUNC, params);
203
+ }
204
+ exports.iterationToExpression = iterationToExpression;
205
+ /**
206
+ * Convert Komaci slot into call to Resolver API for a slot, `s`
207
+ * @param {ModuleMetadata} moduleMetadata collected module metadata about this given component
208
+ * @param {Slot} slot The Slot to be converted into an expression
209
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
210
+ * @returns {Expression} the babel Expression representing the Slot call into the Resolver API
211
+ */
212
+ function slotToExpression(moduleMetadata, slot, iterationContext) {
213
+ const params = [];
214
+ // arg1: Slot Name.
215
+ params.push(t.stringLiteral(slot.name));
216
+ // arg2: Composition configuration.
217
+ params.push(getCompositionConfig(slot, undefined, iterationContext));
218
+ // arg3: Context.
219
+ params.push(types_1.ID.CONTEXT);
220
+ // arg4: Array of expressions for each child.
221
+ const defaultContent = compositionsToArrayExpression(moduleMetadata, slot.compositions, iterationContext);
222
+ if (defaultContent && defaultContent.elements.length) {
223
+ params.push(defaultContent);
224
+ }
225
+ return t.callExpression(types_1.ID.SLOT_FUNC, params);
226
+ }
227
+ exports.slotToExpression = slotToExpression;
228
+ /**
229
+ * Converts Komaci Image into prompt for the Resolver API to make an image priming call
230
+ * @param {GeneratorState} generatorState the current state of the esm generator
231
+ * @param {Image} image the Image node from the KomaciDocument
232
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
233
+ * @returns {Expression} the babel Expression representing the Image prompt into the Resolver API
234
+ */
235
+ function imageToExpression(image, iterationContext) {
236
+ const params = [];
237
+ const funcObjProps = [];
238
+ if ((0, common_shared_1.isCompositionAnImage)(image)) {
239
+ if ((0, common_shared_1.isSrcPrimitiveValue)(image.src)) {
240
+ // type guard ensures `image.src` is a PrimitiveValue
241
+ // lwc-platform will NOT produce an Image KomaciNode with a blank or missing src attribute.
242
+ // However, just in case we do encounter this, we handle it here by simply NOT producing the
243
+ // function ObjectProperty for such a node.
244
+ if (image.src.value &&
245
+ typeof image.src.value === 'string' &&
246
+ image.src.value !== '') {
247
+ funcObjProps.push(t.objectProperty(types_1.ID.IMG_SRC, t.stringLiteral(image.src.value)));
248
+ }
249
+ }
250
+ else if ((0, common_shared_1.isSrcABinding)(image.src)) {
251
+ // type guard ensures `image.src` is a Binding
252
+ // lwc-platform will NOT produce an Image KomaciNode with a blank or missing src attribute.
253
+ // However, just in case we do encounter this, we handle it here by simply NOT producing the
254
+ // function ObjectProperty for such a node.
255
+ if (image.src.value !== '') {
256
+ funcObjProps.push(t.objectProperty(types_1.ID.IMG_SRC, (0, genericAstGeneration_1.bindingToExpression)(image.src, iterationContext)));
257
+ }
258
+ }
259
+ }
260
+ params.push(t.objectExpression(funcObjProps));
261
+ return t.callExpression(types_1.ID.IMG_FUNC, params);
262
+ }
263
+ exports.imageToExpression = imageToExpression;
264
+ /**
265
+ * Creates a babel configuration ObjectExpression for provided composition. This is the `CompositionConfig`
266
+ * from Resolver API in its babel ObjectExpression form.
267
+ * @param {ComposedAdg | Container | Slot} composition the Composition from which to create a configuration (as a ComposedAdg, Container, or Slot)
268
+ * @param {string} componentId the component indentifier, as a string
269
+ * @param {string[]} iterationContext if this is being called from inside an iteration we need that prepend context for bindingToExpression
270
+ * @returns {ObjectExpression} the babel ObjectExpression representing the Resolver API CompositionConfig
271
+ */
272
+ function getCompositionConfig(composition, componentId, iterationContext) {
273
+ const config = [];
274
+ if (composition.slot) {
275
+ config.push(t.objectProperty(types_1.ID.SLOT, t.stringLiteral(composition.slot)));
276
+ }
277
+ // ComposedAdg config contains additional information.
278
+ if (composition.type === 'ComposedAdg') {
279
+ if (componentId) {
280
+ config.push(t.objectProperty(types_1.ID.COMPONENT_ID, t.stringLiteral(componentId)));
281
+ }
282
+ if (composition.properties) {
283
+ const props = [];
284
+ for (const propName of Object.keys(composition.properties)) {
285
+ const prop = composition.properties[propName];
286
+ if (prop.type === 'Binding') {
287
+ props.push(t.objectProperty(t.identifier(propName), (0, genericAstGeneration_1.bindingToExpression)(prop, iterationContext)));
288
+ }
289
+ else if (prop.type === 'PrimitiveValue') {
290
+ props.push(t.objectProperty(t.identifier(propName), (0, genericAstGeneration_1.primitiveToExpression)(prop)));
291
+ }
292
+ }
293
+ config.push(t.objectProperty(types_1.ID.PROPS, t.objectExpression(props)));
294
+ }
295
+ }
296
+ return t.objectExpression(config);
297
+ }
298
+ exports.getCompositionConfig = getCompositionConfig;
299
+ //# sourceMappingURL=compositionAstGeneration.js.map
@@ -0,0 +1,81 @@
1
+ import { NodePath } from '@babel/core';
2
+ import * as t from '@babel/types';
3
+ import { AdgMetadata, HoistedFunctionMetadata, IdKeys, ImportMetadata, ModuleMetadata } from '@komaci/common-shared';
4
+ import { Composition } from '@komaci/types';
5
+ /**
6
+ * Take a local function (getter, template string, etc) and prepare it for the resolvable module
7
+ * - sanitize the function
8
+ * - give the function a module level signature with generated name
9
+ *
10
+ * @param functionMetadata Metadata about the function to hoist
11
+ * @param importMetadata Map of all the import metadata we know about
12
+ *
13
+ * @returns a composed module level function or undefined if we don't have the
14
+ * information for composing the funciton
15
+ */
16
+ export declare function hoistLocalFunction(functionMetadata: HoistedFunctionMetadata, importMetadata: Map<string, ImportMetadata>): t.FunctionDeclaration | undefined;
17
+ /**
18
+ * Take a function defined on a class and sanitize it's interactions in preparation to be hoisted into resolvable module/
19
+ *
20
+ * Two main things happen during sanitization:
21
+ * - references to imports are updated to their generated name (i.e. i2)
22
+ * - references to `this` are replaced with references to `props`
23
+ *
24
+ * @param nodePath The node to sanitize
25
+ * @param importMetadata Metadata about all the imports we know about
26
+ */
27
+ export declare function sanitizeFunction(nodePath: NodePath<t.ClassProperty | t.ClassMethod>, importMetadata: Map<string, ImportMetadata>): void;
28
+ /**
29
+ * Converts a Komaci ADG into a CallExpression to the ADG factory function
30
+ * call for the Resolver API.
31
+ * @param {GeneratorState} generatorState the current state of the esm generator
32
+ * @param {Adg} adg the current ADG to convert into an Expression
33
+ * @returns {t.Expression} Babel Expression representation of the adg() factory function call
34
+ */
35
+ export declare function adgToExpression(adg: AdgMetadata, moduleMetadata: ModuleMetadata): t.CallExpression;
36
+ /**
37
+ * Return the variable declaration done via destructuring the factory object
38
+ * (e.g. const { i, cg } = fct;) or undefined if no fct functions are used.
39
+ * @param factoryFuncs Set of strings that represent used factory functions
40
+ * @returns composed ast statement for factory functions
41
+ */
42
+ export declare function getFactoryFuncDeclaration(factoryFuncs: Set<IdKeys>): t.VariableDeclaration | undefined;
43
+ /**
44
+ * composes ast statements for a given set of ADG Metadata
45
+ *
46
+ * @param adg the metadata for the adg we want to compose an ast for
47
+ * @param moduleMetadata Metadata about the entire module
48
+ * @returns the declaration for a given adg
49
+ */
50
+ export declare function composeAdgFunction(adg: AdgMetadata, moduleMetadata: ModuleMetadata): t.ExportNamedDeclaration | t.ExportDefaultDeclaration | t.FunctionDeclaration;
51
+ /**
52
+ * associate composed adgs with their exported names
53
+ * @param adgName the name of the adg
54
+ * @param exportName the name it will be exported as
55
+ * @returns the composed export statement
56
+ */
57
+ export declare function addExportStatement(adgName: string, exportName: string): t.ExportNamedDeclaration | t.ExportDefaultDeclaration;
58
+ /**
59
+ * Compose the function that calls the `adg` function with all of it's needful info
60
+ * @param {GeneratorState} generatorState the current state of the esm generator
61
+ * @param {Adg} adg The current ADG for which to compose the babel statements
62
+ * @returns the babel statements to represent the function
63
+ */
64
+ export declare function getAdgFunctionBody(adg: AdgMetadata, moduleMetadata: ModuleMetadata): t.BlockStatement;
65
+ /**
66
+ * Converts array of template Compositions into a representation that is an inline function
67
+ * @param {GeneratorState} generatorState the current state of esm-generator
68
+ * @param {Composition[]} compositions array of Compositions to convert
69
+ * @returns {t.ArrowFunctionExpression} an inline ArrowFunctionExpression representing the input Compositions
70
+ */
71
+ export declare function getInlineFunctionFromTemplateCompositions(moduleMetadata: ModuleMetadata, requiredFactoryFunctions: Set<IdKeys>, compositions: Composition[]): t.ArrowFunctionExpression;
72
+ /**
73
+ * A barebones resolvable module default export with a singular node describing the context of an error.
74
+ *
75
+ * We return this instead of a real resolvable module if something throws an error during resolvable module generation
76
+ * @param generatorState The state of the generator for pass through to adgToExpression
77
+ * @param error The error that was thrown
78
+ * @returns A default export representing the error state for this resolvable module
79
+ */
80
+ export declare function produceErrorAdgFunction(moduleMetadata: ModuleMetadata, error: Error): t.Program;
81
+ //# sourceMappingURL=functionAstGeneration.d.ts.map