@komaci/esm-generator 262.15.0 → 262.17.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.
@@ -303,6 +303,42 @@ describe('sanitizeFunction', () => {
303
303
  it('should throw an error if we try to reference a bad input', () => {
304
304
  expect(() => (0, functionAstGeneration_1.sanitizeFunction)(getters[1], imports, new Map())).toThrowError(new Error(`${common_shared_1.ERROR_PREFIX}: 'bad' does not map to valid import`));
305
305
  });
306
+ it('should strip TypeScript non-null assertion operator (!)', () => {
307
+ const sourceWithNonNull = `
308
+ import accessCheck from '@salesforce/accessCheck/SomeCheck.enabled';
309
+ export default class TestComponent {
310
+ get showContent() {
311
+ return accessCheck! && this.isVisible;
312
+ }
313
+ }
314
+ `;
315
+ const ast = (0, common_shared_1.generateAstFromSrcCode)(sourceWithNonNull);
316
+ const { getters } = (0, common_shared_1.getPropertyMetadataFromAst)(ast);
317
+ const imports = new Map();
318
+ imports.set('accessCheck', {
319
+ name: 'accessCheck',
320
+ resourceName: '@salesforce/accessCheck/SomeCheck.enabled',
321
+ staticallyAnalyzable: false,
322
+ usedInPriming: true,
323
+ isFromInternalNamespace: true,
324
+ isFromSupportedLibrary: true,
325
+ generatorAlias: 'i0',
326
+ komaciDocImportRef: '0/names/0',
327
+ });
328
+ (0, functionAstGeneration_1.sanitizeFunction)(getters[0], imports, new Map());
329
+ const hoisted = (0, types_1.functionDeclaration)((0, types_1.identifier)('g0'), [(0, types_1.identifier)('props')], getters[0].node.body);
330
+ const generatedFunction = (0, generator_1.default)((0, types_1.file)((0, types_1.program)([hoisted])));
331
+ // The non-null assertion operator (!) should be removed
332
+ // Should generate: i0 && props.isVisible
333
+ // Should NOT generate: i0! && props.isVisible
334
+ expect(generatedFunction.code).not.toContain('!');
335
+ expect(generatedFunction.code).toContain('i0 && props.isVisible');
336
+ expect(generatedFunction.code).toMatchInlineSnapshot(`
337
+ "function g0(props) {
338
+ return i0 && props.isVisible;
339
+ }"
340
+ `);
341
+ });
306
342
  });
307
343
  describe('adgToExpression', () => {
308
344
  it('returns valid adg function from komaci doc', () => {
@@ -25,6 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const __1 = require("..");
27
27
  const modgen = __importStar(require("../genericAstGeneration"));
28
+ const metadata_1 = require("@lwc/metadata");
28
29
  describe('Handling errors that throw inside a call to generateKomaciModule', () => {
29
30
  it('should return error adg when an error is produced', () => {
30
31
  const input = {
@@ -290,4 +291,103 @@ describe('normalizeSrcFileKeys', () => {
290
291
  expect(input.srcFileMap['templates/test2.html']).not.toBeUndefined();
291
292
  });
292
293
  });
294
+ describe('Bundle processing', () => {
295
+ it('when both .js and .ts files exist with for the component name', () => {
296
+ const bundleSrcFileMap = {
297
+ 'test.js': {},
298
+ 'test.ts': {},
299
+ 'test.html': {},
300
+ };
301
+ const input = {
302
+ moduleInfo: {
303
+ name: 'test',
304
+ namespace: 'c',
305
+ type: 'bundle',
306
+ files: bundleSrcFileMap,
307
+ },
308
+ srcFileMap: {
309
+ 'test.js': 'export default class Test {}',
310
+ 'test.ts': 'export default class Test {}',
311
+ 'test.html': '<template><div>Test</div></template>',
312
+ 'test.css': 'p { text-align: center; }',
313
+ },
314
+ };
315
+ const res = (0, __1.generateKomaciModule)(input);
316
+ expect(res).toContain('ErrorFunction');
317
+ expect(res).toContain('[komaci esm-generator] multiple component script files with the same name found in bundle: test');
318
+ });
319
+ it('can handle multiple script files with the same name in different directories', () => {
320
+ const bundleSrcFileMap = {
321
+ 'test.js': {},
322
+ 'subdir/test.ts': {},
323
+ 'test.html': {},
324
+ };
325
+ const input = {
326
+ moduleInfo: {
327
+ name: 'test',
328
+ namespace: 'c',
329
+ type: 'bundle',
330
+ files: bundleSrcFileMap,
331
+ },
332
+ srcFileMap: {
333
+ 'test.js': 'export default class Test {}',
334
+ 'subdir/test.ts': 'export default class Test {}',
335
+ 'test.html': '<template><div>Test</div></template>',
336
+ 'test.css': 'p { text-align: center; }',
337
+ },
338
+ };
339
+ const res = (0, __1.generateKomaciModule)(input);
340
+ expect(res).not.toContain('ErrorFunction');
341
+ expect(res).toContain('registerAdgFunction');
342
+ });
343
+ it('can handle multiple script files with different names in same directory', () => {
344
+ const testJsSource = `export default class Test extends LightningElement {
345
+ get testProp() {
346
+ return 'test';
347
+ }
348
+ }`;
349
+ const fooTsSource = `export default class Foo {
350
+ get fooProp() {
351
+ return 'foo';
352
+ }
353
+ }`;
354
+ const bundleConfig = {
355
+ namespace: 'c',
356
+ name: 'test',
357
+ type: 'internal',
358
+ files: [
359
+ { fileName: 'test.js', source: testJsSource },
360
+ { fileName: 'foo.ts', source: fooTsSource },
361
+ { fileName: 'test.html', source: '<template><div>Test</div></template>' },
362
+ { fileName: 'test.css', source: 'p { text-align: center; }' },
363
+ ],
364
+ enableKomaci: true,
365
+ namespaceMapping: {},
366
+ npmModuleMapping: {},
367
+ };
368
+ const metadata = (0, metadata_1.collectBundleMetadata)(bundleConfig);
369
+ const inputFiles = Object.fromEntries(metadata.files
370
+ .map(({ fileName, komaciDoc }) => [fileName, komaciDoc])
371
+ .filter(([, komaciDoc]) => !!komaciDoc));
372
+ const input = {
373
+ moduleInfo: {
374
+ name: 'test',
375
+ namespace: 'c',
376
+ type: 'bundle',
377
+ files: inputFiles,
378
+ },
379
+ srcFileMap: {
380
+ 'test.js': testJsSource,
381
+ 'foo.ts': fooTsSource,
382
+ 'test.html': '<template><div>Test</div></template>',
383
+ 'test.css': 'p { text-align: center; }',
384
+ },
385
+ };
386
+ const res = (0, __1.generateKomaciModule)(input);
387
+ expect(res).not.toContain('ErrorFunction');
388
+ expect(res).toContain('registerAdgFunction');
389
+ expect(res).toContain('testProp');
390
+ expect(res).not.toContain('fooProp');
391
+ });
392
+ });
293
393
  //# sourceMappingURL=index.spec.js.map
@@ -112,6 +112,11 @@ function sanitizeFunction(nodePath, importMetadata, gqlMetadataMap) {
112
112
  path.replaceWith(t.memberExpression(t.identifier(common_shared_1.PROPS), path.node.property)); // replace this.<var> with props.<var>
113
113
  }
114
114
  },
115
+ TSNonNullExpression(path) {
116
+ // syntax like foo! is a TypeScript syntax that means "foo is not null or undefined"
117
+ // we need to remove the ! to make the code valid JavaScript
118
+ path.replaceWith(path.node.expression);
119
+ },
115
120
  TaggedTemplateExpression(path) {
116
121
  const taggedTmplExpr = path.node;
117
122
  const taggedTmplLiteral = taggedTmplExpr.quasi;
package/build/index.js CHANGED
@@ -116,38 +116,36 @@ function processGeneratorInputAndState(input) {
116
116
  else if (input.moduleInfo.type === 'bundle') {
117
117
  // code to process a bundle
118
118
  let filename = '', fileExt;
119
- const docMap = input.moduleInfo.files; // {'test.html' : KomaciDoc1, 'test.js' : KomaciDoc2}
120
- const filesMap = {}; // {'html' : {'test.html' : KomaciDoc1}, 'js' : {'test.js' : KomaciDoc2 }}
119
+ const scriptDocs = {}; // {'test.js' : { filename: 'test', komaciDoc: KomaciDoc1 }}
120
+ const htmlDocs = {};
121
121
  let sourceFile;
122
- for (const [fullFilename, komaciDoc] of Object.entries(docMap)) {
122
+ for (const [filePath, komaciDoc] of Object.entries(input.moduleInfo.files)) {
123
123
  // Determine file type based on extension in file name.
124
- const segments = (0, common_shared_1.getFilepathSegments)(fullFilename);
124
+ const segments = (0, common_shared_1.getFilepathSegments)(filePath);
125
125
  filename = segments[0]; // the filename, up to but not including, the file separator character
126
126
  fileExt = segments[segments.length - 1]; // filename extension, not including the separator
127
- let filesObj = {};
128
- // check for existing map entry in order to append to it
129
- // to support multiple files per filetype in the future
130
- if (filesMap[fileExt]) {
131
- filesObj = filesMap[fileExt];
132
- }
133
- filesObj[filename] = komaciDoc;
134
127
  if (fileExt == 'html') {
135
- filesMap['html'] = filesObj;
128
+ htmlDocs[filename] = komaciDoc;
136
129
  }
137
130
  else if (fileExt === 'js' || fileExt === 'ts') {
138
- filesMap['js'] = filesObj;
131
+ scriptDocs[filePath] = { filename, komaciDoc };
139
132
  }
140
133
  else {
141
134
  throw new Error(types_1.ERROR_PREFIX + 'unsupported file extension: ' + fileExt);
142
135
  }
143
136
  }
144
137
  const source = (0, componentAstProcessing_1.getComponentSrcJs)(input);
145
- const komaciJSDoc = filesMap && filesMap['js'] && filesMap['js'][input.moduleInfo.name]
146
- ? filesMap['js'][input.moduleInfo.name]
147
- : {};
148
- const komaciHtmlDocMap = filesMap && filesMap['html'] ? filesMap['html'] : {};
138
+ // Find the main component script file(s)
139
+ const mainComponentScriptFiles = Object.values(scriptDocs).filter(({ filename }) => filename === input.moduleInfo.name);
140
+ // For now we only support one main component script file.
141
+ if (mainComponentScriptFiles.length > 1) {
142
+ throw new Error(types_1.ERROR_PREFIX +
143
+ 'multiple component script files with the same name found in bundle: ' +
144
+ input.moduleInfo.name);
145
+ }
146
+ const uniqueMainComponentScriptDoc = mainComponentScriptFiles[0]?.komaciDoc ?? {};
149
147
  // eslint-disable-next-line prefer-const
150
- sourceFile = (0, genericAstGeneration_1.generateResolvableModule)(input, komaciJSDoc, komaciHtmlDocMap, source);
148
+ sourceFile = (0, genericAstGeneration_1.generateResolvableModule)(input, uniqueMainComponentScriptDoc, htmlDocs, source);
151
149
  // Generate source from constructed AST.
152
150
  const babelOutput = (0, generator_1.default)(sourceFile);
153
151
  return babelOutput.code;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@komaci/esm-generator",
3
- "version": "262.15.0",
3
+ "version": "262.17.0",
4
4
  "description": "Komaci generator for ADG ES modules",
5
5
  "homepage": "https://komaci.dev/",
6
6
  "repository": {