@sola-air-ui/compiler 1.2.0 → 1.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sola-air-ui/compiler",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Compiler for Sola single-file components (.sola) \u2014 transforms template + script + style to ES modules",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/cli.js CHANGED
@@ -18,7 +18,7 @@ if (args.length === 0 || args.includes('-h') || args.includes('--help')) {
18
18
  --target <esm|iife> Output format (default: esm)
19
19
  esm — ES module with import/export (default, for bundlers)
20
20
  iife — Self-contained IIFE for no-bundler environments
21
- (ServiceNow Service Portal, plain <script> tags)
21
+ (enterprise portal widgets, plain <script> tags)
22
22
  --export-name <Name> Global name for IIFE target (default: SolaComponent)
23
23
  The compiled component mounts as window['Name'](el, props)
24
24
  -v, --version Print compiler version
package/src/index.js CHANGED
@@ -6,6 +6,14 @@ const { version: COMPILER_VERSION } = JSON.parse(
6
6
  readFileSync(new URL('../package.json', import.meta.url), 'utf8')
7
7
  );
8
8
 
9
+ // Names every compiled component imports from core under their own name. A
10
+ // script that imports one of these again is not given a second binding.
11
+ const CORE_PROVIDED = new Set([
12
+ 'createSignal', 'createDerived', 'createEffect', 'createIntent', 'createData',
13
+ 'createPersistentSignal', 'onMount', 'onDestroy', 'pushContext', 'popContext',
14
+ '__flush_mounts', '__flush_destroys', '__untrack'
15
+ ]);
16
+
9
17
  const VOID_ELEMENTS = new Set([
10
18
  'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
11
19
  'link', 'meta', 'param', 'source', 'track', 'wbr'
@@ -325,7 +333,7 @@ function preprocessTemplate(template, dynAttrs, handlers) {
325
333
  } else if (hasDyn) {
326
334
  // Build a string-concatenation expression instead of a runtime backtick
327
335
  // template literal. Confirmed by driving a real browser against a live
328
- // ServiceNow Service Portal instance: its widget-script delivery pipeline
336
+ // enterprise portal instance: its widget-script delivery pipeline
329
337
  // silently mangles `${expr}` interpolation inside a template literal down
330
338
  // to bare, unevaluated expression text (e.g. `background: ${x}` becomes
331
339
  // the literal string "background: x" — the function reference itself,
@@ -889,6 +897,12 @@ export function compile(source, options = {}) {
889
897
  const stateVars = new Set();
890
898
  const exportedProps = [];
891
899
  const componentImports = [];
900
+ // Every other import in the script. They used to be deleted, so a package
901
+ // import (`import DataCard from '@sola-air-ui/ui/data-card'`, or anything from
902
+ // '@sola-air-ui/core' that the compiler does not already provide) was gone from
903
+ // the output and left an undefined name behind.
904
+ const otherImports = [];
905
+ const coreImportExtras = [];
892
906
 
893
907
  let reactiveVars = NO_REACTIVE_VARS;
894
908
  if (strippedScript.trim()) {
@@ -914,6 +928,21 @@ export function compile(source, options = {}) {
914
928
  node.specifiers.forEach(spec => {
915
929
  componentImports.push({ localName: spec.local.name, path: src });
916
930
  });
931
+ } else if (src === '@sola-air-ui/core' || src === '@sola/core') {
932
+ // The compiler already imports these names under their own names.
933
+ // Importing one again would be a duplicate binding, so keep only the
934
+ // rest: names it does not provide, and aliased ones.
935
+ node.specifiers.forEach(spec => {
936
+ if (spec.type !== 'ImportSpecifier') return;
937
+ const imported = spec.imported.name ?? spec.imported.value;
938
+ if (spec.local.name === imported && CORE_PROVIDED.has(imported)) return;
939
+ coreImportExtras.push({ imported, local: spec.local.name });
940
+ });
941
+ } else {
942
+ otherImports.push({
943
+ code: strippedScript.slice(node.start, node.end).trim().replace(/;?$/, ';'),
944
+ locals: node.specifiers.map(spec => spec.local.name)
945
+ });
917
946
  }
918
947
  edits.push({
919
948
  start: node.start,
@@ -1050,6 +1079,11 @@ export function compile(source, options = {}) {
1050
1079
  let uid = 0;
1051
1080
  let domCode = '';
1052
1081
  const importedComponentSet = new Set(componentImports.map(i => i.localName));
1082
+ // A capitalised tag that matches a name imported from a package is a component
1083
+ // too (`import DataCard from '@sola-air-ui/ui/data-card'`), not only a `.sola` path.
1084
+ for (const imp of otherImports) {
1085
+ for (const name of imp.locals) if (/^[A-Z]/.test(name)) importedComponentSet.add(name);
1086
+ }
1053
1087
 
1054
1088
  const sourceFile = options.filename || '<component>';
1055
1089
 
@@ -1130,25 +1164,43 @@ export function compile(source, options = {}) {
1130
1164
  domCode += ` ${parentVar}.appendChild(${cid}_target);\n`;
1131
1165
 
1132
1166
  // Dynamically-bound props (rows={items}) arrive here as __soladyn_N__ placeholders —
1133
- // resolve them back to the real expression from dynAttrs and pass it as a raw
1134
- // (unquoted) property so the child receives live data, not the placeholder text.
1167
+ // resolve them back to the real expression from dynAttrs.
1135
1168
  //
1136
1169
  // `onXxx`-named props (e.g. onChange={handler}) arrive as a
1137
1170
  // __solahandler_N__ marker, because preprocessTemplate cannot tell a
1138
1171
  // component apart from a native element and lifts both the same way.
1139
1172
  // Either way the expression is passed through as a live function.
1173
+ //
1174
+ // Three kinds of dynamic prop:
1175
+ // - a bare name (rows={items}) is passed as-is. For a $state that is the
1176
+ // signal accessor, which is how a child receives live data (the shipped
1177
+ // components accept either an accessor or a plain value);
1178
+ // - an expression that reads a signal (title={ctx.title}) is evaluated
1179
+ // with the signal reads rewritten, and the child is re-mounted when
1180
+ // the value changes;
1181
+ // - an expression that reads no signal (text={msg.text} in an {#each})
1182
+ // is evaluated once, when the child is mounted.
1140
1183
  const propEntries = [];
1184
+ let reactiveProps = false;
1141
1185
  for (const [key, val] of Object.entries(node.attribs || {})) {
1142
1186
  const dynMatch = /^__soladyn_(\d+)__$/.exec(val);
1143
1187
  const handlerMatch = /^__solahandler_(\d+)__$/.exec(val);
1144
- // Dynamic (non-event) component props are deliberately NOT auto-called:
1145
- // passing the getter is how a child receives live data today, and
1146
- // README-syntax components rely on it.
1147
- const propValue = dynMatch
1148
- ? `(${dynAttrs[parseInt(dynMatch[1], 10)]})`
1149
- : handlerMatch
1150
- ? `(${rewrite(handlers[parseInt(handlerMatch[1], 10)])})`
1151
- : JSON.stringify(val);
1188
+ let propValue;
1189
+ if (dynMatch) {
1190
+ const raw = dynAttrs[parseInt(dynMatch[1], 10)];
1191
+ if (/^\s*[A-Za-z_$][\w$]*\s*$/.test(raw)) {
1192
+ propValue = `(${raw})`;
1193
+ } else {
1194
+ checkExpression(raw, 'component prop');
1195
+ const rewritten = rewrite(raw);
1196
+ if (rewritten !== raw) reactiveProps = true;
1197
+ propValue = `(${rewritten})`;
1198
+ }
1199
+ } else if (handlerMatch) {
1200
+ propValue = `(${rewrite(handlers[parseInt(handlerMatch[1], 10)])})`;
1201
+ } else {
1202
+ propValue = JSON.stringify(val);
1203
+ }
1152
1204
  propEntries.push(`${JSON.stringify(key)}: ${propValue}`);
1153
1205
  }
1154
1206
 
@@ -1162,7 +1214,21 @@ export function compile(source, options = {}) {
1162
1214
  propEntries.push(`children: ${slotVar}`);
1163
1215
  }
1164
1216
 
1165
- domCode += ` ${node.name}(${cid}_target, { ${propEntries.join(', ')} });\n`;
1217
+ // The child mounts untracked, so nothing it reads while building itself
1218
+ // can re-run the parent's effect. Its teardown is kept and registered with
1219
+ // whatever scope is being built, so it runs when that scope is destroyed.
1220
+ domCode += ` let ${cid}_unmount = null;\n`;
1221
+ domCode += ` onDestroy(() => { if (typeof ${cid}_unmount === 'function') ${cid}_unmount(); ${cid}_unmount = null; });\n`;
1222
+ if (reactiveProps) {
1223
+ domCode += ` createEffect(() => {\n`;
1224
+ domCode += ` const ${cid}_props = { ${propEntries.join(', ')} };\n`;
1225
+ domCode += ` if (typeof ${cid}_unmount === 'function') __untrack(${cid}_unmount);\n`;
1226
+ domCode += ` ${cid}_target.textContent = '';\n`;
1227
+ domCode += ` ${cid}_unmount = __untrack(() => ${node.name}(${cid}_target, ${cid}_props));\n`;
1228
+ domCode += ` });\n`;
1229
+ } else {
1230
+ domCode += ` ${cid}_unmount = __untrack(() => ${node.name}(${cid}_target, { ${propEntries.join(', ')} }));\n`;
1231
+ }
1166
1232
  return;
1167
1233
  }
1168
1234
 
@@ -1173,37 +1239,50 @@ export function compile(source, options = {}) {
1173
1239
  }
1174
1240
 
1175
1241
  // {#if ...} {:else} ... {/if}
1242
+ //
1243
+ // Each time a branch is built it gets its own scope (pushContext). Effects,
1244
+ // onDestroy callbacks and child components created inside register with that
1245
+ // scope, and switching or removing the branch destroys it, so nothing built
1246
+ // for a branch that is no longer on the page keeps running.
1176
1247
  if (node.name === 'sola-if') {
1177
1248
  const cid = `c${uid++}`;
1178
1249
  domCode += ` const ${cid}_a = document.createComment('if');\n`;
1179
1250
  domCode += ` ${parentVar}.appendChild(${cid}_a);\n`;
1180
1251
  domCode += ` let ${cid}_els = [];\n`;
1181
-
1252
+ domCode += ` let ${cid}_ctx = null;\n`;
1253
+ domCode += ` onDestroy(() => { if (${cid}_ctx) { __flush_destroys(${cid}_ctx); ${cid}_ctx = null; } });\n`;
1254
+
1182
1255
  const thenChild = node.children.find(c => c.name === 'sola-then');
1183
1256
  const elseChild = node.children.find(c => c.name === 'sola-else');
1184
1257
 
1185
- domCode += ` createEffect(() => {\n`;
1186
- domCode += ` ${cid}_els.forEach(e => e.remove()); ${cid}_els = [];\n`;
1187
- domCode += ` if (${rewrite(node.attribs.condition)}) {\n`;
1188
- if (thenChild) {
1258
+ const emitBranch = (branch) => {
1259
+ if (!branch) return;
1260
+ domCode += ` ${cid}_ctx = pushContext();\n`;
1261
+ domCode += ` try {\n`;
1189
1262
  domCode += ` const f = document.createDocumentFragment();\n`;
1190
- thenChild.children.forEach(child => emitNode(child, 'f', locals));
1263
+ branch.children.forEach(child => emitNode(child, 'f', locals));
1191
1264
  domCode += ` Array.from(f.childNodes).forEach(n => ${cid}_els.push(n));\n`;
1192
1265
  domCode += ` ${cid}_a.parentNode.insertBefore(f, ${cid}_a.nextSibling);\n`;
1193
- }
1266
+ domCode += ` } finally { popContext(${cid}_ctx); }\n`;
1267
+ };
1268
+
1269
+ domCode += ` createEffect(() => {\n`;
1270
+ domCode += ` if (${cid}_ctx) { __flush_destroys(${cid}_ctx); ${cid}_ctx = null; }\n`;
1271
+ domCode += ` ${cid}_els.forEach(e => e.remove()); ${cid}_els = [];\n`;
1272
+ domCode += ` if (${rewrite(node.attribs.condition)}) {\n`;
1273
+ emitBranch(thenChild);
1194
1274
  domCode += ` } else {\n`;
1195
- if (elseChild) {
1196
- domCode += ` const f = document.createDocumentFragment();\n`;
1197
- elseChild.children.forEach(child => emitNode(child, 'f', locals));
1198
- domCode += ` Array.from(f.childNodes).forEach(n => ${cid}_els.push(n));\n`;
1199
- domCode += ` ${cid}_a.parentNode.insertBefore(f, ${cid}_a.nextSibling);\n`;
1200
- }
1275
+ emitBranch(elseChild);
1201
1276
  domCode += ` }\n`;
1202
1277
  domCode += ` });\n`;
1203
1278
  return;
1204
1279
  }
1205
1280
 
1206
1281
  // {#each} with optional keyed diffing: {#each items as item (item.id)}
1282
+ //
1283
+ // Like {#if}, what is built for the list gets its own scope so it can be
1284
+ // destroyed: the whole list for an unkeyed each, one scope per key for a
1285
+ // keyed one (so removing an item stops that item's effects and children).
1207
1286
  if (node.name === 'sola-each') {
1208
1287
  const eid = `e${uid++}`;
1209
1288
  // Item/index names shadow signals inside the loop body and key expression
@@ -1217,70 +1296,53 @@ export function compile(source, options = {}) {
1217
1296
  domCode += ` const ${eid}_a = document.createComment('each');\n`;
1218
1297
  domCode += ` ${parentVar}.appendChild(${eid}_a);\n`;
1219
1298
  if (keyExpr) {
1220
- // Keyed: maintain a Map<key, Node[]> and reconcile on each run
1299
+ // Keyed: maintain a Map<key, { nodes, ctx }> and reconcile on each run
1221
1300
  // Reconcile by walking the new order and moving each key's nodes into
1222
1301
  // place against a cursor. The previous version only ever inserted, and
1223
1302
  // against an anchor it never advanced — so reordering a keyed list (a
1224
1303
  // sort, a drag, a reverse) left the DOM in its original order, silently.
1225
- domCode += ` let ${eid}_keyMap = new Map();
1226
- `;
1227
- domCode += ` createEffect(() => {
1228
- `;
1229
- domCode += ` const _items = ${arrayExpr} || [];
1230
- `;
1231
- domCode += ` const _parent = ${eid}_a.parentNode;
1232
- `;
1233
- domCode += ` const _seen = new Set();
1234
- `;
1235
- domCode += ` let _cursor = ${eid}_a.nextSibling;
1236
- `;
1237
- domCode += ` for (let _i = 0; _i < _items.length; _i++) {
1238
- `;
1239
- domCode += ` const ${node.attribs.item} = _items[_i];
1240
- `;
1241
- if (node.attribs.index) domCode += ` const ${node.attribs.index} = _i;
1242
- `;
1243
- domCode += ` const _key = String(${keyExpr});
1244
- `;
1245
- domCode += ` _seen.add(_key);
1246
- `;
1247
- domCode += ` let _nodes = ${eid}_keyMap.get(_key);
1248
- `;
1249
- domCode += ` if (!_nodes) {
1250
- `;
1251
- domCode += ` const f = document.createDocumentFragment();
1252
- `;
1304
+ domCode += ` let ${eid}_keyMap = new Map();\n`;
1305
+ domCode += ` onDestroy(() => { for (const _e of ${eid}_keyMap.values()) __flush_destroys(_e.ctx); ${eid}_keyMap.clear(); });\n`;
1306
+ domCode += ` createEffect(() => {\n`;
1307
+ domCode += ` const _items = ${arrayExpr} || [];\n`;
1308
+ domCode += ` const _parent = ${eid}_a.parentNode;\n`;
1309
+ domCode += ` const _seen = new Set();\n`;
1310
+ domCode += ` let _cursor = ${eid}_a.nextSibling;\n`;
1311
+ domCode += ` for (let _i = 0; _i < _items.length; _i++) {\n`;
1312
+ domCode += ` const ${node.attribs.item} = _items[_i];\n`;
1313
+ if (node.attribs.index) domCode += ` const ${node.attribs.index} = _i;\n`;
1314
+ domCode += ` const _key = String(${keyExpr});\n`;
1315
+ domCode += ` _seen.add(_key);\n`;
1316
+ domCode += ` let _entry = ${eid}_keyMap.get(_key);\n`;
1317
+ domCode += ` if (!_entry) {\n`;
1318
+ domCode += ` const _kctx = pushContext();\n`;
1319
+ domCode += ` try {\n`;
1320
+ domCode += ` const f = document.createDocumentFragment();\n`;
1253
1321
  node.children.forEach(child => emitNode(child, 'f', eachLocals));
1254
- domCode += ` _nodes = Array.from(f.childNodes);
1255
- `;
1256
- domCode += ` ${eid}_keyMap.set(_key, _nodes);
1257
- `;
1258
- domCode += ` }
1259
- `;
1260
- domCode += ` for (const _n of _nodes) {
1261
- `;
1262
- domCode += ` if (_n === _cursor) { _cursor = _cursor.nextSibling; }
1263
- `;
1264
- domCode += ` else { _parent.insertBefore(_n, _cursor); }
1265
- `;
1266
- domCode += ` }
1267
- `;
1268
- domCode += ` }
1269
- `;
1270
- domCode += ` for (const [_k, _stale] of ${eid}_keyMap) {
1271
- `;
1272
- domCode += ` if (!_seen.has(_k)) { _stale.forEach(n => n.remove()); ${eid}_keyMap.delete(_k); }
1273
- `;
1274
- domCode += ` }
1275
- `;
1276
- domCode += ` });
1277
- `;
1322
+ domCode += ` _entry = { nodes: Array.from(f.childNodes), ctx: _kctx };\n`;
1323
+ domCode += ` } finally { popContext(_kctx); }\n`;
1324
+ domCode += ` ${eid}_keyMap.set(_key, _entry);\n`;
1325
+ domCode += ` }\n`;
1326
+ domCode += ` for (const _n of _entry.nodes) {\n`;
1327
+ domCode += ` if (_n === _cursor) { _cursor = _cursor.nextSibling; }\n`;
1328
+ domCode += ` else { _parent.insertBefore(_n, _cursor); }\n`;
1329
+ domCode += ` }\n`;
1330
+ domCode += ` }\n`;
1331
+ domCode += ` for (const [_k, _stale] of ${eid}_keyMap) {\n`;
1332
+ domCode += ` if (!_seen.has(_k)) { __flush_destroys(_stale.ctx); _stale.nodes.forEach(n => n.remove()); ${eid}_keyMap.delete(_k); }\n`;
1333
+ domCode += ` }\n`;
1334
+ domCode += ` });\n`;
1278
1335
  } else {
1279
1336
  // Unkeyed: full teardown + rebuild
1280
1337
  domCode += ` let ${eid}_els = [];\n`;
1338
+ domCode += ` let ${eid}_ctx = null;\n`;
1339
+ domCode += ` onDestroy(() => { if (${eid}_ctx) { __flush_destroys(${eid}_ctx); ${eid}_ctx = null; } });\n`;
1281
1340
  domCode += ` createEffect(() => {\n`;
1341
+ domCode += ` if (${eid}_ctx) { __flush_destroys(${eid}_ctx); ${eid}_ctx = null; }\n`;
1282
1342
  domCode += ` ${eid}_els.forEach(e => e.remove()); ${eid}_els = [];\n`;
1283
1343
  domCode += ` const _items = ${arrayExpr} || [];\n`;
1344
+ domCode += ` ${eid}_ctx = pushContext();\n`;
1345
+ domCode += ` try {\n`;
1284
1346
  domCode += ` const f = document.createDocumentFragment();\n`;
1285
1347
  domCode += ` for (let _i = 0; _i < _items.length; _i++) {\n`;
1286
1348
  domCode += ` const ${node.attribs.item} = _items[_i];\n`;
@@ -1289,6 +1351,7 @@ export function compile(source, options = {}) {
1289
1351
  domCode += ` }\n`;
1290
1352
  domCode += ` Array.from(f.childNodes).forEach(n => ${eid}_els.push(n));\n`;
1291
1353
  domCode += ` ${eid}_a.parentNode.insertBefore(f, ${eid}_a.nextSibling);\n`;
1354
+ domCode += ` } finally { popContext(${eid}_ctx); }\n`;
1292
1355
  domCode += ` });\n`;
1293
1356
  }
1294
1357
  return;
@@ -1356,7 +1419,7 @@ export function compile(source, options = {}) {
1356
1419
  root.children.forEach(child => emitNode(child, '__target'));
1357
1420
 
1358
1421
  // Assemble final output module
1359
- const CORE_EXPORTS = 'createSignal, createDerived, createEffect, createIntent, createData, createPersistentSignal, onMount, onDestroy, pushContext, popContext, __flush_mounts, __flush_destroys';
1422
+ const CORE_EXPORTS = [...CORE_PROVIDED].join(', ');
1360
1423
  // The default bus is imported under an alias so a user variable named `bus`
1361
1424
  // cannot shadow what $on / $lastEvent compile to.
1362
1425
  const ESM_CORE_IMPORTS = CORE_EXPORTS + ', bus as __solaBus';
@@ -1365,19 +1428,30 @@ export function compile(source, options = {}) {
1365
1428
  output += `// Compiled by @sola-air-ui/compiler v${COMPILER_VERSION}\n`;
1366
1429
 
1367
1430
  if (target === 'iife') {
1368
- // ServiceNow / no-bundler mode: pull from window.SolaCore global
1431
+ // No-bundler mode: pull from window.SolaCore global
1369
1432
  output += `(function() {\n`;
1370
- output += `const { ${IIFE_CORE_PULL} } = window.SolaCore;\n`;
1433
+ const iifeExtras = coreImportExtras.map(e => (e.local === e.imported ? e.imported : `${e.imported}: ${e.local}`));
1434
+ output += `const { ${[IIFE_CORE_PULL, ...iifeExtras].join(', ')} } = window.SolaCore;\n`;
1371
1435
  for (const imp of componentImports) {
1372
1436
  output += `// Note: sub-component ${imp.localName} must be pre-loaded before this script\n`;
1373
1437
  }
1438
+ for (const imp of otherImports) {
1439
+ output += `// Note: ${imp.locals.join(', ')} must be loaded before this script (no-bundler output cannot import)\n`;
1440
+ }
1374
1441
  output += `\n`;
1375
1442
  output += `window['${options.exportName || 'SolaComponent'}'] = function mount(__target, props = {}) {\n`;
1376
1443
  } else {
1377
1444
  output += `import { ${ESM_CORE_IMPORTS} } from '@sola-air-ui/core';\n`;
1445
+ if (coreImportExtras.length) {
1446
+ const names = coreImportExtras.map(e => (e.local === e.imported ? e.imported : `${e.imported} as ${e.local}`));
1447
+ output += `import { ${names.join(', ')} } from '@sola-air-ui/core';\n`;
1448
+ }
1378
1449
  for (const imp of componentImports) {
1379
1450
  output += `import ${imp.localName} from '${imp.path}';\n`;
1380
1451
  }
1452
+ for (const imp of otherImports) {
1453
+ output += `${imp.code}\n`;
1454
+ }
1381
1455
  output += `\n`;
1382
1456
  output += `export default function mount(__target, props = {}) {\n`;
1383
1457
  }
@@ -1462,6 +1536,9 @@ function inferPropType(defaultSrc) {
1462
1536
  if (/^(['"`])[\s\S]*\1$/.test(d)) return 'string';
1463
1537
  if (/^-?\d[\d_]*(\.\d+)?([eE][+-]?\d+)?$/.test(d)) return 'number';
1464
1538
  if (d === 'true' || d === 'false') return 'boolean';
1539
+ // A null or undefined default says nothing about the type. `unknown` would stop a
1540
+ // TypeScript host from reading or calling the prop; `any` lets it.
1541
+ if (d === 'null' || d === 'undefined') return 'any';
1465
1542
  if (d.startsWith('[')) return 'unknown[]';
1466
1543
  if (d.startsWith('{')) return 'Record<string, unknown>';
1467
1544
  if (/^(\(.*\)|\w+)\s*=>|^function\b/.test(d)) return '(...args: any[]) => any';
package/types/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export interface CompileOptions {
4
4
  /**
5
5
  * 'esm' (default) emits a module importing from @sola-air-ui/core.
6
6
  * 'iife' emits a self-contained bundle reading from window.SolaCore, for
7
- * ServiceNow and other no-bundler hosts.
7
+ * enterprise portals and other no-bundler hosts.
8
8
  */
9
9
  target?: 'esm' | 'iife';
10
10
  /** Global name the IIFE build registers itself under. Default 'SolaComponent'. */