@stencil/angular-output-target 1.3.2 → 1.4.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.
@@ -1,5 +1,8 @@
1
1
  import { EOL } from 'os';
2
2
  import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = path.dirname(__filename);
3
6
  import { OutputTypes } from './utils';
4
7
  export default async function generateValueAccessors(compilerCtx, components, outputTarget, config) {
5
8
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
@@ -15,10 +18,13 @@ export default async function generateValueAccessors(compilerCtx, components, ou
15
18
  allElementSelectors = allAccessors[type].elementSelectors;
16
19
  allEventTargets = allAccessors[type].eventTargets;
17
20
  }
18
- return Object.assign(Object.assign({}, allAccessors), { [type]: {
21
+ return {
22
+ ...allAccessors,
23
+ [type]: {
19
24
  elementSelectors: allElementSelectors.concat(elementSelectors),
20
25
  eventTargets: allEventTargets.concat([[va.event, va.targetAttr]]),
21
- } });
26
+ },
27
+ };
22
28
  }, {});
23
29
  await Promise.all(Object.keys(normalizedValueAccessors).map(async (type) => {
24
30
  const valueAccessorType = type; // Object.keys converts to string
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var path = require('path');
6
+ var url = require('url');
6
7
  var os = require('os');
7
8
 
8
9
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -69,11 +70,10 @@ function relativeImport(pathFrom, pathTo, ext) {
69
70
  return normalizePath(`${relativePath}/${path__default["default"].basename(pathTo, ext)}`);
70
71
  }
71
72
  async function readPackageJson(config, rootDir) {
72
- var _a;
73
73
  const pkgJsonPath = path__default["default"].join(rootDir, 'package.json');
74
74
  let pkgJson;
75
75
  try {
76
- pkgJson = (await ((_a = config.sys) === null || _a === void 0 ? void 0 : _a.readFile(pkgJsonPath, 'utf8')));
76
+ pkgJson = (await config.sys?.readFile(pkgJsonPath, 'utf8'));
77
77
  }
78
78
  catch (e) {
79
79
  throw new Error(`Missing "package.json" file for distribution: ${pkgJsonPath}`);
@@ -394,6 +394,8 @@ export const DIRECTIVES = [
394
394
  return compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
395
395
  }
396
396
 
397
+ const __filename$2 = url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
398
+ const __dirname$2 = path__default["default"].dirname(__filename$2);
397
399
  async function generateValueAccessors(compilerCtx, components, outputTarget, config) {
398
400
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
399
401
  return;
@@ -408,16 +410,19 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
408
410
  allElementSelectors = allAccessors[type].elementSelectors;
409
411
  allEventTargets = allAccessors[type].eventTargets;
410
412
  }
411
- return Object.assign(Object.assign({}, allAccessors), { [type]: {
413
+ return {
414
+ ...allAccessors,
415
+ [type]: {
412
416
  elementSelectors: allElementSelectors.concat(elementSelectors),
413
417
  eventTargets: allEventTargets.concat([[va.event, va.targetAttr]]),
414
- } });
418
+ },
419
+ };
415
420
  }, {});
416
421
  await Promise.all(Object.keys(normalizedValueAccessors).map(async (type) => {
417
422
  const valueAccessorType = type; // Object.keys converts to string
418
423
  const targetFileName = `${type}-value-accessor.ts`;
419
424
  const targetFilePath = path__default["default"].join(targetDir, targetFileName);
420
- const srcFilePath = path__default["default"].join(__dirname, '../resources/control-value-accessors/', targetFileName);
425
+ const srcFilePath = path__default["default"].join(__dirname$2, '../resources/control-value-accessors/', targetFileName);
421
426
  const srcFileContents = await compilerCtx.fs.readFile(srcFilePath);
422
427
  const finalText = createValueAccessor(srcFileContents, normalizedValueAccessors[valueAccessorType], outputTarget.outputType);
423
428
  await compilerCtx.fs.writeFile(targetFilePath, finalText);
@@ -437,7 +442,7 @@ function copyResources$1(config, resourcesFilesToCopy, directory) {
437
442
  }
438
443
  const copyTasks = resourcesFilesToCopy.map((rf) => {
439
444
  return {
440
- src: path__default["default"].join(__dirname, '../resources/control-value-accessors/', rf),
445
+ src: path__default["default"].join(__dirname$2, '../resources/control-value-accessors/', rf),
441
446
  dest: path__default["default"].join(directory, rf),
442
447
  keepDirStructure: false,
443
448
  warn: false,
@@ -775,6 +780,8 @@ stencilSetTagTransformer(\${transformerArg});
775
780
  await compilerCtx.fs.writeFile(path__default["default"].join(scriptsDirectory, 'patch-transform-selectors.mjs'), patchSelectorsContent);
776
781
  }
777
782
 
783
+ const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('index.cjs', document.baseURI).href)));
784
+ const __dirname$1 = path__default["default"].dirname(__filename$1);
778
785
  async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
779
786
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
780
787
  const rootDir = config.rootDir;
@@ -791,7 +798,7 @@ async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components
791
798
  const proxiesDir = path__default["default"].dirname(outputTarget.directivesProxyFile);
792
799
  for (const component of filteredComponents) {
793
800
  const componentFile = path__default["default"].join(proxiesDir, `${component.tagName}.ts`);
794
- const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir);
801
+ const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir, config);
795
802
  tasks.push(compilerCtx.fs.writeFile(componentFile, componentText));
796
803
  }
797
804
  // Generate barrel file that re-exports all components
@@ -802,7 +809,7 @@ async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components
802
809
  }
803
810
  else {
804
811
  // Generate single file with all components (original behavior)
805
- const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir);
812
+ const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir, config);
806
813
  tasks.push(compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText));
807
814
  tasks.push(generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget));
808
815
  }
@@ -839,7 +846,7 @@ async function copyResources(config, outputTarget) {
839
846
  if (!config.sys || !config.sys.copy || !config.sys.glob) {
840
847
  throw new Error('stencil is not properly initialized at this step. Notify the developer');
841
848
  }
842
- const srcDirectory = path__default["default"].join(__dirname, '..', 'angular-component-lib');
849
+ const srcDirectory = path__default["default"].join(__dirname$1, '..', 'angular-component-lib');
843
850
  const destDirectory = path__default["default"].join(path__default["default"].dirname(outputTarget.directivesProxyFile), 'angular-component-lib');
844
851
  return config.sys.copy([
845
852
  {
@@ -851,7 +858,7 @@ async function copyResources(config, outputTarget) {
851
858
  },
852
859
  ], srcDirectory);
853
860
  }
854
- function generateProxies(components, pkgData, outputTarget, rootDir) {
861
+ function generateProxies(components, pkgData, outputTarget, rootDir, config) {
855
862
  const distTypesDir = path__default["default"].dirname(pkgData.types);
856
863
  const dtsFilePath = path__default["default"].join(rootDir, distTypesDir, GENERATED_DTS);
857
864
  const { outputType } = outputTarget;
@@ -887,10 +894,9 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
887
894
  * otherwise we risk bundlers pulling in lazy loaded imports.
888
895
  */
889
896
  const generateTypeImports = () => {
890
- let importLocation = outputTarget.componentCorePackage
891
- ? normalizePath(outputTarget.componentCorePackage)
897
+ const importLocation = outputTarget.componentCorePackage
898
+ ? getPathToComponentTypes(config, outputTarget)
892
899
  : normalizePath(componentsTypeFile);
893
- importLocation += isCustomElementsBuild ? `/${outputTarget.customElementsDir}` : '';
894
900
  return `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
895
901
  };
896
902
  const typeImports = generateTypeImports();
@@ -911,13 +917,10 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
911
917
  const proxyFileOutput = [];
912
918
  const filterInternalProps = (prop) => !prop.internal;
913
919
  // Ensure that virtual properties has required as false.
914
- const mapInputProp = (prop) => {
915
- var _a;
916
- return ({
917
- name: prop.name,
918
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
919
- });
920
- };
920
+ const mapInputProp = (prop) => ({
921
+ name: prop.name,
922
+ required: prop.required ?? false,
923
+ });
921
924
  const { componentCorePackage, customElementsDir } = outputTarget;
922
925
  for (let cmpMeta of components) {
923
926
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -956,8 +959,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
956
959
  /**
957
960
  * Generate a single component proxy file for ES modules output
958
961
  */
959
- function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir) {
960
- var _a;
962
+ function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir, config) {
961
963
  const { outputType, componentCorePackage, customElementsDir } = outputTarget;
962
964
  const distTypesDir = path__default["default"].dirname(pkgData.types);
963
965
  const dtsFilePath = path__default["default"].join(rootDir, distTypesDir, GENERATED_DTS);
@@ -966,7 +968,7 @@ function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir) {
966
968
  const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputType);
967
969
  const isStandaloneBuild = outputType === OutputTypes.Standalone;
968
970
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
969
- const hasOutputs = (_a = cmpMeta.events) === null || _a === void 0 ? void 0 : _a.some((event) => !event.internal);
971
+ const hasOutputs = cmpMeta.events?.some((event) => !event.internal);
970
972
  // Angular core imports for this component
971
973
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef', 'NgZone'];
972
974
  if (hasOutputs) {
@@ -981,8 +983,9 @@ ${createImportStatement(angularCoreImports, '@angular/core')}
981
983
 
982
984
  ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
983
985
  // Type imports
984
- let importLocation = componentCorePackage ? normalizePath(componentCorePackage) : normalizePath(componentsTypeFile);
985
- importLocation += isCustomElementsBuild ? `/${customElementsDir}` : '';
986
+ const importLocation = componentCorePackage
987
+ ? getPathToComponentTypes(config, outputTarget)
988
+ : normalizePath(componentsTypeFile);
986
989
  const typeImports = `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
987
990
  // defineCustomElement import
988
991
  let sourceImport = '';
@@ -991,13 +994,10 @@ ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
991
994
  }
992
995
  // Generate component definition
993
996
  const filterInternalProps = (prop) => !prop.internal;
994
- const mapInputProp = (prop) => {
995
- var _a;
996
- return ({
997
- name: prop.name,
998
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
999
- });
1000
- };
997
+ const mapInputProp = (prop) => ({
998
+ name: prop.name,
999
+ required: prop.required ?? false,
1000
+ });
1001
1001
  const internalProps = [];
1002
1002
  if (cmpMeta.properties) {
1003
1003
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
@@ -1043,6 +1043,22 @@ function generateBarrelFile(components, outputTarget) {
1043
1043
  .join('\n');
1044
1044
  return header + exports + '\n';
1045
1045
  }
1046
+ function getPathToComponentTypes(config, outputTarget) {
1047
+ const basePkg = outputTarget.componentCorePackage || '';
1048
+ // in v5, all types (including components.d.ts) are generated in the dist/types directory
1049
+ const typesTarget = config.outputTargets?.find((o) => o.type === 'types');
1050
+ if (typesTarget) {
1051
+ const rawDir = typesTarget.dir || 'dist/types';
1052
+ const relDir = config.rootDir && path__default["default"].isAbsolute(rawDir) ? path__default["default"].relative(config.rootDir, rawDir) : rawDir;
1053
+ return normalizePath(path__default["default"].join(basePkg, relDir, 'components'));
1054
+ }
1055
+ // v4: append customElementsDir for custom elements build, otherwise package root
1056
+ const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputTarget.outputType);
1057
+ if (isCustomElementsBuild && outputTarget.customElementsDir) {
1058
+ return normalizePath(path__default["default"].join(basePkg, outputTarget.customElementsDir));
1059
+ }
1060
+ return normalizePath(basePkg);
1061
+ }
1046
1062
  const GENERATED_DTS = 'components.d.ts';
1047
1063
  const IMPORT_TYPES = 'Components';
1048
1064
 
@@ -1062,8 +1078,13 @@ const angularOutputTarget = (outputTarget) => {
1062
1078
  };
1063
1079
  };
1064
1080
  function normalizeOutputTarget(config, outputTarget) {
1065
- var _a, _b;
1066
- const results = Object.assign(Object.assign({}, outputTarget), { excludeComponents: outputTarget.excludeComponents || [], valueAccessorConfigs: outputTarget.valueAccessorConfigs || [], customElementsDir: (_a = outputTarget.customElementsDir) !== null && _a !== void 0 ? _a : 'components', outputType: (_b = outputTarget.outputType) !== null && _b !== void 0 ? _b : OutputTypes.Standalone });
1081
+ const results = {
1082
+ ...outputTarget,
1083
+ excludeComponents: outputTarget.excludeComponents || [],
1084
+ valueAccessorConfigs: outputTarget.valueAccessorConfigs || [],
1085
+ customElementsDir: outputTarget.customElementsDir ?? 'components',
1086
+ outputType: outputTarget.outputType ?? OutputTypes.Standalone,
1087
+ };
1067
1088
  if (config.rootDir == null) {
1068
1089
  throw new Error('rootDir is not set and it should be set by stencil itself');
1069
1090
  }
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import path from 'path';
2
+ import { fileURLToPath } from 'url';
2
3
  import { EOL } from 'os';
3
4
 
4
5
  const OutputTypes = {
@@ -61,11 +62,10 @@ function relativeImport(pathFrom, pathTo, ext) {
61
62
  return normalizePath(`${relativePath}/${path.basename(pathTo, ext)}`);
62
63
  }
63
64
  async function readPackageJson(config, rootDir) {
64
- var _a;
65
65
  const pkgJsonPath = path.join(rootDir, 'package.json');
66
66
  let pkgJson;
67
67
  try {
68
- pkgJson = (await ((_a = config.sys) === null || _a === void 0 ? void 0 : _a.readFile(pkgJsonPath, 'utf8')));
68
+ pkgJson = (await config.sys?.readFile(pkgJsonPath, 'utf8'));
69
69
  }
70
70
  catch (e) {
71
71
  throw new Error(`Missing "package.json" file for distribution: ${pkgJsonPath}`);
@@ -386,6 +386,8 @@ export const DIRECTIVES = [
386
386
  return compilerCtx.fs.writeFile(outputTarget.directivesArrayFile, c);
387
387
  }
388
388
 
389
+ const __filename$1 = fileURLToPath(import.meta.url);
390
+ const __dirname$1 = path.dirname(__filename$1);
389
391
  async function generateValueAccessors(compilerCtx, components, outputTarget, config) {
390
392
  if (!Array.isArray(outputTarget.valueAccessorConfigs) || outputTarget.valueAccessorConfigs.length === 0) {
391
393
  return;
@@ -400,16 +402,19 @@ async function generateValueAccessors(compilerCtx, components, outputTarget, con
400
402
  allElementSelectors = allAccessors[type].elementSelectors;
401
403
  allEventTargets = allAccessors[type].eventTargets;
402
404
  }
403
- return Object.assign(Object.assign({}, allAccessors), { [type]: {
405
+ return {
406
+ ...allAccessors,
407
+ [type]: {
404
408
  elementSelectors: allElementSelectors.concat(elementSelectors),
405
409
  eventTargets: allEventTargets.concat([[va.event, va.targetAttr]]),
406
- } });
410
+ },
411
+ };
407
412
  }, {});
408
413
  await Promise.all(Object.keys(normalizedValueAccessors).map(async (type) => {
409
414
  const valueAccessorType = type; // Object.keys converts to string
410
415
  const targetFileName = `${type}-value-accessor.ts`;
411
416
  const targetFilePath = path.join(targetDir, targetFileName);
412
- const srcFilePath = path.join(__dirname, '../resources/control-value-accessors/', targetFileName);
417
+ const srcFilePath = path.join(__dirname$1, '../resources/control-value-accessors/', targetFileName);
413
418
  const srcFileContents = await compilerCtx.fs.readFile(srcFilePath);
414
419
  const finalText = createValueAccessor(srcFileContents, normalizedValueAccessors[valueAccessorType], outputTarget.outputType);
415
420
  await compilerCtx.fs.writeFile(targetFilePath, finalText);
@@ -429,7 +434,7 @@ function copyResources$1(config, resourcesFilesToCopy, directory) {
429
434
  }
430
435
  const copyTasks = resourcesFilesToCopy.map((rf) => {
431
436
  return {
432
- src: path.join(__dirname, '../resources/control-value-accessors/', rf),
437
+ src: path.join(__dirname$1, '../resources/control-value-accessors/', rf),
433
438
  dest: path.join(directory, rf),
434
439
  keepDirStructure: false,
435
440
  warn: false,
@@ -767,6 +772,8 @@ stencilSetTagTransformer(\${transformerArg});
767
772
  await compilerCtx.fs.writeFile(path.join(scriptsDirectory, 'patch-transform-selectors.mjs'), patchSelectorsContent);
768
773
  }
769
774
 
775
+ const __filename = fileURLToPath(import.meta.url);
776
+ const __dirname = path.dirname(__filename);
770
777
  async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components, config) {
771
778
  const filteredComponents = getFilteredComponents(outputTarget.excludeComponents, components);
772
779
  const rootDir = config.rootDir;
@@ -783,7 +790,7 @@ async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components
783
790
  const proxiesDir = path.dirname(outputTarget.directivesProxyFile);
784
791
  for (const component of filteredComponents) {
785
792
  const componentFile = path.join(proxiesDir, `${component.tagName}.ts`);
786
- const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir);
793
+ const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir, config);
787
794
  tasks.push(compilerCtx.fs.writeFile(componentFile, componentText));
788
795
  }
789
796
  // Generate barrel file that re-exports all components
@@ -794,7 +801,7 @@ async function angularDirectiveProxyOutput(compilerCtx, outputTarget, components
794
801
  }
795
802
  else {
796
803
  // Generate single file with all components (original behavior)
797
- const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir);
804
+ const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir, config);
798
805
  tasks.push(compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText));
799
806
  tasks.push(generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget));
800
807
  }
@@ -843,7 +850,7 @@ async function copyResources(config, outputTarget) {
843
850
  },
844
851
  ], srcDirectory);
845
852
  }
846
- function generateProxies(components, pkgData, outputTarget, rootDir) {
853
+ function generateProxies(components, pkgData, outputTarget, rootDir, config) {
847
854
  const distTypesDir = path.dirname(pkgData.types);
848
855
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
849
856
  const { outputType } = outputTarget;
@@ -879,10 +886,9 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
879
886
  * otherwise we risk bundlers pulling in lazy loaded imports.
880
887
  */
881
888
  const generateTypeImports = () => {
882
- let importLocation = outputTarget.componentCorePackage
883
- ? normalizePath(outputTarget.componentCorePackage)
889
+ const importLocation = outputTarget.componentCorePackage
890
+ ? getPathToComponentTypes(config, outputTarget)
884
891
  : normalizePath(componentsTypeFile);
885
- importLocation += isCustomElementsBuild ? `/${outputTarget.customElementsDir}` : '';
886
892
  return `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
887
893
  };
888
894
  const typeImports = generateTypeImports();
@@ -903,13 +909,10 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
903
909
  const proxyFileOutput = [];
904
910
  const filterInternalProps = (prop) => !prop.internal;
905
911
  // Ensure that virtual properties has required as false.
906
- const mapInputProp = (prop) => {
907
- var _a;
908
- return ({
909
- name: prop.name,
910
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
911
- });
912
- };
912
+ const mapInputProp = (prop) => ({
913
+ name: prop.name,
914
+ required: prop.required ?? false,
915
+ });
913
916
  const { componentCorePackage, customElementsDir } = outputTarget;
914
917
  for (let cmpMeta of components) {
915
918
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -948,8 +951,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
948
951
  /**
949
952
  * Generate a single component proxy file for ES modules output
950
953
  */
951
- function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir) {
952
- var _a;
954
+ function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir, config) {
953
955
  const { outputType, componentCorePackage, customElementsDir } = outputTarget;
954
956
  const distTypesDir = path.dirname(pkgData.types);
955
957
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
@@ -958,7 +960,7 @@ function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir) {
958
960
  const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputType);
959
961
  const isStandaloneBuild = outputType === OutputTypes.Standalone;
960
962
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
961
- const hasOutputs = (_a = cmpMeta.events) === null || _a === void 0 ? void 0 : _a.some((event) => !event.internal);
963
+ const hasOutputs = cmpMeta.events?.some((event) => !event.internal);
962
964
  // Angular core imports for this component
963
965
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef', 'NgZone'];
964
966
  if (hasOutputs) {
@@ -973,8 +975,9 @@ ${createImportStatement(angularCoreImports, '@angular/core')}
973
975
 
974
976
  ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
975
977
  // Type imports
976
- let importLocation = componentCorePackage ? normalizePath(componentCorePackage) : normalizePath(componentsTypeFile);
977
- importLocation += isCustomElementsBuild ? `/${customElementsDir}` : '';
978
+ const importLocation = componentCorePackage
979
+ ? getPathToComponentTypes(config, outputTarget)
980
+ : normalizePath(componentsTypeFile);
978
981
  const typeImports = `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
979
982
  // defineCustomElement import
980
983
  let sourceImport = '';
@@ -983,13 +986,10 @@ ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
983
986
  }
984
987
  // Generate component definition
985
988
  const filterInternalProps = (prop) => !prop.internal;
986
- const mapInputProp = (prop) => {
987
- var _a;
988
- return ({
989
- name: prop.name,
990
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
991
- });
992
- };
989
+ const mapInputProp = (prop) => ({
990
+ name: prop.name,
991
+ required: prop.required ?? false,
992
+ });
993
993
  const internalProps = [];
994
994
  if (cmpMeta.properties) {
995
995
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
@@ -1035,6 +1035,22 @@ function generateBarrelFile(components, outputTarget) {
1035
1035
  .join('\n');
1036
1036
  return header + exports + '\n';
1037
1037
  }
1038
+ function getPathToComponentTypes(config, outputTarget) {
1039
+ const basePkg = outputTarget.componentCorePackage || '';
1040
+ // in v5, all types (including components.d.ts) are generated in the dist/types directory
1041
+ const typesTarget = config.outputTargets?.find((o) => o.type === 'types');
1042
+ if (typesTarget) {
1043
+ const rawDir = typesTarget.dir || 'dist/types';
1044
+ const relDir = config.rootDir && path.isAbsolute(rawDir) ? path.relative(config.rootDir, rawDir) : rawDir;
1045
+ return normalizePath(path.join(basePkg, relDir, 'components'));
1046
+ }
1047
+ // v4: append customElementsDir for custom elements build, otherwise package root
1048
+ const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputTarget.outputType);
1049
+ if (isCustomElementsBuild && outputTarget.customElementsDir) {
1050
+ return normalizePath(path.join(basePkg, outputTarget.customElementsDir));
1051
+ }
1052
+ return normalizePath(basePkg);
1053
+ }
1038
1054
  const GENERATED_DTS = 'components.d.ts';
1039
1055
  const IMPORT_TYPES = 'Components';
1040
1056
 
@@ -1054,8 +1070,13 @@ const angularOutputTarget = (outputTarget) => {
1054
1070
  };
1055
1071
  };
1056
1072
  function normalizeOutputTarget(config, outputTarget) {
1057
- var _a, _b;
1058
- const results = Object.assign(Object.assign({}, outputTarget), { excludeComponents: outputTarget.excludeComponents || [], valueAccessorConfigs: outputTarget.valueAccessorConfigs || [], customElementsDir: (_a = outputTarget.customElementsDir) !== null && _a !== void 0 ? _a : 'components', outputType: (_b = outputTarget.outputType) !== null && _b !== void 0 ? _b : OutputTypes.Standalone });
1073
+ const results = {
1074
+ ...outputTarget,
1075
+ excludeComponents: outputTarget.excludeComponents || [],
1076
+ valueAccessorConfigs: outputTarget.valueAccessorConfigs || [],
1077
+ customElementsDir: outputTarget.customElementsDir ?? 'components',
1078
+ outputType: outputTarget.outputType ?? OutputTypes.Standalone,
1079
+ };
1059
1080
  if (config.rootDir == null) {
1060
1081
  throw new Error('rootDir is not set and it should be set by stencil itself');
1061
1082
  }
@@ -1,12 +1,13 @@
1
1
  import type { CompilerCtx, ComponentCompilerMeta, Config } from '@stencil/core/internal';
2
2
  import type { OutputTargetAngular, PackageJSON } from './types';
3
3
  export declare function angularDirectiveProxyOutput(compilerCtx: CompilerCtx, outputTarget: OutputTargetAngular, components: ComponentCompilerMeta[], config: Config): Promise<void>;
4
- export declare function generateProxies(components: ComponentCompilerMeta[], pkgData: PackageJSON, outputTarget: OutputTargetAngular, rootDir: string): string;
4
+ export declare function generateProxies(components: ComponentCompilerMeta[], pkgData: PackageJSON, outputTarget: OutputTargetAngular, rootDir: string, config: Config): string;
5
5
  /**
6
6
  * Generate a single component proxy file for ES modules output
7
7
  */
8
- export declare function generateComponentProxy(cmpMeta: ComponentCompilerMeta, pkgData: PackageJSON, outputTarget: OutputTargetAngular, rootDir: string): string;
8
+ export declare function generateComponentProxy(cmpMeta: ComponentCompilerMeta, pkgData: PackageJSON, outputTarget: OutputTargetAngular, rootDir: string, config: Config): string;
9
9
  /**
10
10
  * Generate a barrel file that re-exports all components
11
11
  */
12
12
  export declare function generateBarrelFile(components: ComponentCompilerMeta[], outputTarget: OutputTargetAngular): string;
13
+ export declare function getPathToComponentTypes(config: Config, outputTarget: OutputTargetAngular): string;
@@ -1,4 +1,7 @@
1
1
  import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ const __filename = fileURLToPath(import.meta.url);
4
+ const __dirname = path.dirname(__filename);
2
5
  import { relativeImport, normalizePath, sortBy, readPackageJson, dashToPascalCase, createImportStatement, isOutputTypeCustomElementsBuild, OutputTypes, mapPropName, } from './utils';
3
6
  import { createAngularComponentDefinition, createComponentTypeDefinition } from './generate-angular-component';
4
7
  import { generateAngularDirectivesFile } from './generate-angular-directives-file';
@@ -21,7 +24,7 @@ export async function angularDirectiveProxyOutput(compilerCtx, outputTarget, com
21
24
  const proxiesDir = path.dirname(outputTarget.directivesProxyFile);
22
25
  for (const component of filteredComponents) {
23
26
  const componentFile = path.join(proxiesDir, `${component.tagName}.ts`);
24
- const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir);
27
+ const componentText = generateComponentProxy(component, pkgData, outputTarget, rootDir, config);
25
28
  tasks.push(compilerCtx.fs.writeFile(componentFile, componentText));
26
29
  }
27
30
  // Generate barrel file that re-exports all components
@@ -32,7 +35,7 @@ export async function angularDirectiveProxyOutput(compilerCtx, outputTarget, com
32
35
  }
33
36
  else {
34
37
  // Generate single file with all components (original behavior)
35
- const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir);
38
+ const finalText = generateProxies(filteredComponents, pkgData, outputTarget, rootDir, config);
36
39
  tasks.push(compilerCtx.fs.writeFile(outputTarget.directivesProxyFile, finalText));
37
40
  tasks.push(generateAngularDirectivesFile(compilerCtx, filteredComponents, outputTarget));
38
41
  }
@@ -81,7 +84,7 @@ async function copyResources(config, outputTarget) {
81
84
  },
82
85
  ], srcDirectory);
83
86
  }
84
- export function generateProxies(components, pkgData, outputTarget, rootDir) {
87
+ export function generateProxies(components, pkgData, outputTarget, rootDir, config) {
85
88
  const distTypesDir = path.dirname(pkgData.types);
86
89
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
87
90
  const { outputType } = outputTarget;
@@ -117,10 +120,9 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
117
120
  * otherwise we risk bundlers pulling in lazy loaded imports.
118
121
  */
119
122
  const generateTypeImports = () => {
120
- let importLocation = outputTarget.componentCorePackage
121
- ? normalizePath(outputTarget.componentCorePackage)
123
+ const importLocation = outputTarget.componentCorePackage
124
+ ? getPathToComponentTypes(config, outputTarget)
122
125
  : normalizePath(componentsTypeFile);
123
- importLocation += isCustomElementsBuild ? `/${outputTarget.customElementsDir}` : '';
124
126
  return `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
125
127
  };
126
128
  const typeImports = generateTypeImports();
@@ -141,13 +143,10 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
141
143
  const proxyFileOutput = [];
142
144
  const filterInternalProps = (prop) => !prop.internal;
143
145
  // Ensure that virtual properties has required as false.
144
- const mapInputProp = (prop) => {
145
- var _a;
146
- return ({
147
- name: prop.name,
148
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
149
- });
150
- };
146
+ const mapInputProp = (prop) => ({
147
+ name: prop.name,
148
+ required: prop.required ?? false,
149
+ });
151
150
  const { componentCorePackage, customElementsDir } = outputTarget;
152
151
  for (let cmpMeta of components) {
153
152
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
@@ -186,8 +185,7 @@ ${createImportStatement(componentLibImports, './angular-component-lib/utils')}\n
186
185
  /**
187
186
  * Generate a single component proxy file for ES modules output
188
187
  */
189
- export function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir) {
190
- var _a;
188
+ export function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir, config) {
191
189
  const { outputType, componentCorePackage, customElementsDir } = outputTarget;
192
190
  const distTypesDir = path.dirname(pkgData.types);
193
191
  const dtsFilePath = path.join(rootDir, distTypesDir, GENERATED_DTS);
@@ -196,7 +194,7 @@ export function generateComponentProxy(cmpMeta, pkgData, outputTarget, rootDir)
196
194
  const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputType);
197
195
  const isStandaloneBuild = outputType === OutputTypes.Standalone;
198
196
  const tagNameAsPascal = dashToPascalCase(cmpMeta.tagName);
199
- const hasOutputs = (_a = cmpMeta.events) === null || _a === void 0 ? void 0 : _a.some((event) => !event.internal);
197
+ const hasOutputs = cmpMeta.events?.some((event) => !event.internal);
200
198
  // Angular core imports for this component
201
199
  const angularCoreImports = ['ChangeDetectionStrategy', 'ChangeDetectorRef', 'Component', 'ElementRef', 'NgZone'];
202
200
  if (hasOutputs) {
@@ -211,8 +209,9 @@ ${createImportStatement(angularCoreImports, '@angular/core')}
211
209
 
212
210
  ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
213
211
  // Type imports
214
- let importLocation = componentCorePackage ? normalizePath(componentCorePackage) : normalizePath(componentsTypeFile);
215
- importLocation += isCustomElementsBuild ? `/${customElementsDir}` : '';
212
+ const importLocation = componentCorePackage
213
+ ? getPathToComponentTypes(config, outputTarget)
214
+ : normalizePath(componentsTypeFile);
216
215
  const typeImports = `import ${isCustomElementsBuild ? 'type ' : ''}{ ${IMPORT_TYPES} } from '${importLocation}';\n`;
217
216
  // defineCustomElement import
218
217
  let sourceImport = '';
@@ -221,13 +220,10 @@ ${createImportStatement(['ProxyCmp'], './angular-component-lib/utils')}\n`;
221
220
  }
222
221
  // Generate component definition
223
222
  const filterInternalProps = (prop) => !prop.internal;
224
- const mapInputProp = (prop) => {
225
- var _a;
226
- return ({
227
- name: prop.name,
228
- required: (_a = prop.required) !== null && _a !== void 0 ? _a : false,
229
- });
230
- };
223
+ const mapInputProp = (prop) => ({
224
+ name: prop.name,
225
+ required: prop.required ?? false,
226
+ });
231
227
  const internalProps = [];
232
228
  if (cmpMeta.properties) {
233
229
  internalProps.push(...cmpMeta.properties.filter(filterInternalProps));
@@ -273,5 +269,21 @@ export function generateBarrelFile(components, outputTarget) {
273
269
  .join('\n');
274
270
  return header + exports + '\n';
275
271
  }
272
+ export function getPathToComponentTypes(config, outputTarget) {
273
+ const basePkg = outputTarget.componentCorePackage || '';
274
+ // in v5, all types (including components.d.ts) are generated in the dist/types directory
275
+ const typesTarget = config.outputTargets?.find((o) => o.type === 'types');
276
+ if (typesTarget) {
277
+ const rawDir = typesTarget.dir || 'dist/types';
278
+ const relDir = config.rootDir && path.isAbsolute(rawDir) ? path.relative(config.rootDir, rawDir) : rawDir;
279
+ return normalizePath(path.join(basePkg, relDir, 'components'));
280
+ }
281
+ // v4: append customElementsDir for custom elements build, otherwise package root
282
+ const isCustomElementsBuild = isOutputTypeCustomElementsBuild(outputTarget.outputType);
283
+ if (isCustomElementsBuild && outputTarget.customElementsDir) {
284
+ return normalizePath(path.join(basePkg, outputTarget.customElementsDir));
285
+ }
286
+ return normalizePath(basePkg);
287
+ }
276
288
  const GENERATED_DTS = 'components.d.ts';
277
289
  const IMPORT_TYPES = 'Components';
package/dist/plugin.js CHANGED
@@ -17,8 +17,13 @@ export const angularOutputTarget = (outputTarget) => {
17
17
  };
18
18
  };
19
19
  export function normalizeOutputTarget(config, outputTarget) {
20
- var _a, _b;
21
- const results = Object.assign(Object.assign({}, outputTarget), { excludeComponents: outputTarget.excludeComponents || [], valueAccessorConfigs: outputTarget.valueAccessorConfigs || [], customElementsDir: (_a = outputTarget.customElementsDir) !== null && _a !== void 0 ? _a : 'components', outputType: (_b = outputTarget.outputType) !== null && _b !== void 0 ? _b : OutputTypes.Standalone });
20
+ const results = {
21
+ ...outputTarget,
22
+ excludeComponents: outputTarget.excludeComponents || [],
23
+ valueAccessorConfigs: outputTarget.valueAccessorConfigs || [],
24
+ customElementsDir: outputTarget.customElementsDir ?? 'components',
25
+ outputType: outputTarget.outputType ?? OutputTypes.Standalone,
26
+ };
22
27
  if (config.rootDir == null) {
23
28
  throw new Error('rootDir is not set and it should be set by stencil itself');
24
29
  }
package/dist/utils.js CHANGED
@@ -62,11 +62,10 @@ export function isRelativePath(path) {
62
62
  return path && path.startsWith('.');
63
63
  }
64
64
  export async function readPackageJson(config, rootDir) {
65
- var _a;
66
65
  const pkgJsonPath = path.join(rootDir, 'package.json');
67
66
  let pkgJson;
68
67
  try {
69
- pkgJson = (await ((_a = config.sys) === null || _a === void 0 ? void 0 : _a.readFile(pkgJsonPath, 'utf8')));
68
+ pkgJson = (await config.sys?.readFile(pkgJsonPath, 'utf8'));
70
69
  }
71
70
  catch (e) {
72
71
  throw new Error(`Missing "package.json" file for distribution: ${pkgJsonPath}`);
@@ -0,0 +1,9 @@
1
+ import type { WizardContext } from '@stencil/cli';
2
+ export declare const wizard: {
3
+ init: {
4
+ id: string;
5
+ displayName: string;
6
+ description: string;
7
+ run({ config, workspaceRoot, prompts, nypm }: WizardContext): Promise<void>;
8
+ };
9
+ };
package/dist/wizard.js ADDED
@@ -0,0 +1,334 @@
1
+ import { Project, SyntaxKind } from 'ts-morph';
2
+ import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
3
+ import { join, relative, dirname } from 'node:path';
4
+ // ---------------------------------------------------------------------------
5
+ // ts-morph helpers
6
+ // ---------------------------------------------------------------------------
7
+ function amendStencilConfig(configPath, targetCode) {
8
+ const project = new Project({ skipAddingFilesFromTsConfig: true });
9
+ const src = project.addSourceFileAtPath(configPath);
10
+ if (!src.getImportDeclaration('@stencil/angular-output-target')) {
11
+ src.addImportDeclaration({
12
+ moduleSpecifier: '@stencil/angular-output-target',
13
+ namedImports: ['angularOutputTarget'],
14
+ });
15
+ }
16
+ const existingProp = src
17
+ .getDescendantsOfKind(SyntaxKind.PropertyAssignment)
18
+ .find((p) => p.getName() === 'outputTargets');
19
+ if (!existingProp) {
20
+ const configObj = src.getVariableDeclaration('config')?.getInitializerIfKind(SyntaxKind.ObjectLiteralExpression) ??
21
+ src
22
+ .getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression)
23
+ .find((obj) => obj.getProperty('namespace') !== undefined);
24
+ if (!configObj)
25
+ throw new Error('Could not find Stencil config object in stencil.config.ts');
26
+ configObj.addPropertyAssignment({ name: 'outputTargets', initializer: '[]' });
27
+ }
28
+ const prop = src.getDescendantsOfKind(SyntaxKind.PropertyAssignment).find((p) => p.getName() === 'outputTargets');
29
+ const arr = prop.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);
30
+ if (!arr)
31
+ throw new Error('outputTargets is not an array literal in stencil.config.ts');
32
+ const existing = arr.getText();
33
+ const alreadyAdded = existing.includes('angularOutputTarget(');
34
+ // Filter out any existing angularOutputTarget call so it can be replaced cleanly
35
+ const elements = arr
36
+ .getElements()
37
+ .map((e) => e.getText().trim())
38
+ .filter((e) => !e.includes('angularOutputTarget('));
39
+ const hasStandalone = existing.includes("type: 'standalone'") ||
40
+ existing.includes('type: "standalone"') ||
41
+ existing.includes("type: 'dist-custom-elements'") ||
42
+ existing.includes('type: "dist-custom-elements"');
43
+ if (!hasStandalone)
44
+ elements.push("{ type: 'standalone' }");
45
+ elements.push(targetCode);
46
+ prop.setInitializer(`[\n${elements.map((e) => ` ${e}`).join(',\n')},\n]`);
47
+ src.formatText();
48
+ src.saveSync();
49
+ return !alreadyAdded;
50
+ }
51
+ // ---------------------------------------------------------------------------
52
+ // pnpm build approval
53
+ // ---------------------------------------------------------------------------
54
+ async function allowPnpmBuild(pkg, rootDir, workspaceRoot) {
55
+ const base = workspaceRoot ?? rootDir;
56
+ const workspaceYaml = join(base, 'pnpm-workspace.yaml');
57
+ if (await pathExists(workspaceYaml)) {
58
+ let content = await readFile(workspaceYaml, 'utf8');
59
+ // onlyBuiltDependencies (list form)
60
+ if (!content.includes(`- '${pkg}'`) && !content.includes(`- "${pkg}"`) && !content.includes(`- ${pkg}\n`)) {
61
+ if (content.includes('onlyBuiltDependencies:')) {
62
+ content = content.replace(/^(onlyBuiltDependencies:[ \t]*\n)/m, `$1 - ${pkg}\n`);
63
+ }
64
+ else {
65
+ content += `\nonlyBuiltDependencies:\n - ${pkg}\n`;
66
+ }
67
+ }
68
+ // allowBuilds (map form, pnpm 11+)
69
+ if (!content.includes(`${pkg}: true`)) {
70
+ if (content.includes('allowBuilds:')) {
71
+ content = content.replace(/^(allowBuilds:[ \t]*\n)/m, `$1 ${pkg}: true\n`);
72
+ }
73
+ else {
74
+ content += `\nallowBuilds:\n ${pkg}: true\n`;
75
+ }
76
+ }
77
+ await writeFile(workspaceYaml, content, 'utf8');
78
+ return;
79
+ }
80
+ // Non-workspace: amend root package.json pnpm field
81
+ const rootPkgPath = join(base, 'package.json');
82
+ try {
83
+ const rootPkg = JSON.parse(await readFile(rootPkgPath, 'utf8'));
84
+ const existingList = rootPkg?.pnpm?.onlyBuiltDependencies ?? [];
85
+ const existingMap = rootPkg?.pnpm?.allowBuilds ?? {};
86
+ rootPkg.pnpm = {
87
+ ...rootPkg.pnpm,
88
+ onlyBuiltDependencies: existingList.includes(pkg) ? existingList : [...existingList, pkg],
89
+ allowBuilds: { ...existingMap, [pkg]: true },
90
+ };
91
+ await writeFile(rootPkgPath, JSON.stringify(rootPkg, null, 2) + '\n', 'utf8');
92
+ }
93
+ catch {
94
+ // no root package.json — nothing to amend
95
+ }
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Wrapper package scaffolding
99
+ // ---------------------------------------------------------------------------
100
+ async function pathExists(p) {
101
+ try {
102
+ await access(p);
103
+ return true;
104
+ }
105
+ catch {
106
+ return false;
107
+ }
108
+ }
109
+ function toPascalCase(s) {
110
+ return s
111
+ .split(/[-_]/)
112
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
113
+ .join('');
114
+ }
115
+ async function scaffoldWrapperPackage(wrapperDir, packageName, corePackageName, corePkgVersion, namespace, outputType) {
116
+ const libDir = join(wrapperDir, 'src', 'lib');
117
+ await mkdir(libDir, { recursive: true });
118
+ const className = toPascalCase(namespace);
119
+ const pkgJson = {
120
+ name: packageName,
121
+ version: '0.0.1',
122
+ scripts: { build: 'ng-packagr -p ng-package.json' },
123
+ peerDependencies: {
124
+ '@angular/common': '>=19',
125
+ '@angular/core': '>=19',
126
+ },
127
+ dependencies: { [corePackageName]: corePkgVersion },
128
+ devDependencies: {
129
+ '@angular/common': '>=19',
130
+ '@angular/core': '>=19',
131
+ '@angular/compiler': '>=19',
132
+ '@angular/compiler-cli': '>=19',
133
+ 'ng-packagr': '>=19',
134
+ rxjs: '>=6',
135
+ tslib: '>=2',
136
+ typescript: '>=4 <7',
137
+ },
138
+ };
139
+ const ngPackage = {
140
+ lib: { entryFile: 'src/index.ts' },
141
+ deleteDestPath: false,
142
+ allowedNonPeerDependencies: [corePackageName],
143
+ };
144
+ const tsConfig = {
145
+ compilerOptions: {
146
+ target: 'ES2022',
147
+ module: 'ES2022',
148
+ moduleResolution: 'bundler',
149
+ experimentalDecorators: true,
150
+ strict: true,
151
+ skipLibCheck: true,
152
+ },
153
+ include: ['src/**/*.ts'],
154
+ };
155
+ const tsConfigLib = {
156
+ extends: './tsconfig.json',
157
+ compilerOptions: { declaration: false, inlineSources: true },
158
+ angularCompilerOptions: { compilationMode: 'partial' },
159
+ };
160
+ // NgModule file — only needed for 'component' outputType
161
+ let ngModuleTs;
162
+ if (outputType === 'component') {
163
+ ngModuleTs =
164
+ `import { NgModule } from '@angular/core';\n` +
165
+ `import { DIRECTIVES } from './directives.array';\n\n` +
166
+ `@NgModule({\n` +
167
+ ` declarations: [...DIRECTIVES],\n` +
168
+ ` exports: [...DIRECTIVES],\n` +
169
+ `})\n` +
170
+ `export class ${className}Module {}\n`;
171
+ }
172
+ // src/index.ts — public API surface
173
+ // directives.ts (the directivesProxyFile) sits at src/lib/directives.ts
174
+ let indexTs = `// Public API — re-exports generated by @stencil/angular-output-target.\n`;
175
+ indexTs += `export * from './lib/directives';\n`;
176
+ if (outputType === 'component') {
177
+ indexTs += `export * from './lib/${namespace}.module';\n`;
178
+ }
179
+ await Promise.all([
180
+ writeFile(join(wrapperDir, '.gitignore'), 'dist/\nnode_modules/\n.angular/\n', 'utf8'),
181
+ writeFile(join(wrapperDir, 'package.json'), JSON.stringify(pkgJson, null, 2) + '\n', 'utf8'),
182
+ writeFile(join(wrapperDir, 'ng-package.json'), JSON.stringify(ngPackage, null, 2) + '\n', 'utf8'),
183
+ writeFile(join(wrapperDir, 'tsconfig.json'), JSON.stringify(tsConfig, null, 2) + '\n', 'utf8'),
184
+ writeFile(join(wrapperDir, 'tsconfig.lib.json'), JSON.stringify(tsConfigLib, null, 2) + '\n', 'utf8'),
185
+ writeFile(join(wrapperDir, 'src', 'index.ts'), indexTs, 'utf8'),
186
+ ...(ngModuleTs ? [writeFile(join(libDir, `${namespace}.module.ts`), ngModuleTs, 'utf8')] : []),
187
+ ]);
188
+ }
189
+ // ---------------------------------------------------------------------------
190
+ // Wizard
191
+ // ---------------------------------------------------------------------------
192
+ export const wizard = {
193
+ init: {
194
+ id: '@stencil/angular-output-target',
195
+ displayName: 'Angular',
196
+ description: 'Angular component wrappers for your Stencil components',
197
+ async run({ config, workspaceRoot, prompts, nypm }) {
198
+ const { intro, outro, text, select, confirm, spinner, isCancel, cancel, log } = prompts;
199
+ intro('Angular output target');
200
+ const stencilConfigPath = join(config.rootDir, 'stencil.config.ts');
201
+ // Guard: already configured?
202
+ const guardProject = new Project({ skipAddingFilesFromTsConfig: true });
203
+ const alreadyConfigured = guardProject
204
+ .addSourceFileAtPath(stencilConfigPath)
205
+ .getDescendantsOfKind(SyntaxKind.PropertyAssignment)
206
+ .find((p) => p.getName() === 'outputTargets')
207
+ ?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression)
208
+ ?.getText()
209
+ .includes('angularOutputTarget(');
210
+ if (alreadyConfigured) {
211
+ const redo = await confirm({
212
+ message: 'angularOutputTarget is already in stencil.config.ts — reconfigure?',
213
+ initialValue: false,
214
+ });
215
+ if (isCancel(redo) || !redo) {
216
+ cancel('Skipping Angular setup.');
217
+ return;
218
+ }
219
+ }
220
+ // Where should the wrapper package live?
221
+ let wrapperDir;
222
+ const defaultName = `${config.fsNamespace}-angular`;
223
+ if (workspaceRoot) {
224
+ const rawName = await text({
225
+ message: 'Wrapper package name?',
226
+ placeholder: defaultName,
227
+ defaultValue: defaultName,
228
+ });
229
+ if (isCancel(rawName)) {
230
+ cancel('Setup cancelled.');
231
+ return;
232
+ }
233
+ wrapperDir = join(dirname(config.rootDir), rawName);
234
+ }
235
+ else {
236
+ const defaultRel = `../${config.fsNamespace}-angular`;
237
+ const rawDir = await text({
238
+ message: 'Wrapper package directory? (relative to stencil.config.ts)',
239
+ placeholder: defaultRel,
240
+ defaultValue: defaultRel,
241
+ });
242
+ if (isCancel(rawDir)) {
243
+ cancel('Setup cancelled.');
244
+ return;
245
+ }
246
+ wrapperDir = join(config.rootDir, rawDir);
247
+ }
248
+ // Angular component type — drives what we scaffold
249
+ const outputType = await select({
250
+ message: 'Angular component type?',
251
+ options: [
252
+ { value: 'standalone', label: 'Standalone', hint: 'Modern Angular (v19+) — no NgModule' },
253
+ { value: 'component', label: 'NgModule', hint: 'Classic — all components in one module' },
254
+ { value: 'scam', label: 'SCAM', hint: 'One NgModule per component' },
255
+ ],
256
+ });
257
+ if (isCancel(outputType)) {
258
+ cancel('Setup cancelled.');
259
+ return;
260
+ }
261
+ const selectedOutputType = outputType;
262
+ // Derive stencil.config-relative paths from the wrapper location
263
+ const directivesProxyFile = relative(config.rootDir, join(wrapperDir, 'src', 'lib', 'directives.ts')).replace(/\\/g, '/');
264
+ const directivesArrayFile = selectedOutputType === 'component'
265
+ ? relative(config.rootDir, join(wrapperDir, 'src', 'lib', 'directives.array.ts')).replace(/\\/g, '/')
266
+ : undefined;
267
+ const componentCorePackage = config.fsNamespace;
268
+ // Scaffold wrapper package if the directory doesn't exist yet
269
+ const shouldScaffold = !(await pathExists(wrapperDir));
270
+ if (shouldScaffold) {
271
+ const s = spinner();
272
+ s.start(`Scaffolding wrapper package at ${relative(workspaceRoot ?? config.rootDir, wrapperDir)}`);
273
+ try {
274
+ const corePkgVersion = workspaceRoot ? 'workspace:*' : `file:${relative(wrapperDir, config.rootDir)}`;
275
+ await scaffoldWrapperPackage(wrapperDir, `${config.fsNamespace}-angular`, componentCorePackage, corePkgVersion, config.fsNamespace, selectedOutputType);
276
+ s.stop('Wrapper package scaffolded');
277
+ }
278
+ catch (e) {
279
+ s.stop('Scaffolding failed — continuing');
280
+ log.warn(`Could not scaffold wrapper package: ${e}`);
281
+ }
282
+ }
283
+ // Ensure esbuild (used by ng-packagr) is allowed to run install scripts in pnpm workspaces
284
+ try {
285
+ await allowPnpmBuild('esbuild', config.rootDir, workspaceRoot);
286
+ }
287
+ catch {
288
+ // non-fatal — user can run `pnpm approve-builds` manually
289
+ }
290
+ // Derive customElementsDir from an existing standalone target, or use the v5 default
291
+ const standaloneTarget = config.outputTargets?.find((o) => o.type === 'standalone');
292
+ const customElementsDir = standaloneTarget?.dir
293
+ ? relative(config.rootDir, standaloneTarget.dir).replace(/\\/g, '/')
294
+ : 'dist/standalone';
295
+ // Build target config
296
+ const lines = [
297
+ `componentCorePackage: '${componentCorePackage}'`,
298
+ `customElementsDir: '${customElementsDir}'`,
299
+ `directivesProxyFile: '${directivesProxyFile}'`,
300
+ ...(directivesArrayFile ? [`directivesArrayFile: '${directivesArrayFile}'`] : []),
301
+ ...(selectedOutputType !== 'standalone' ? [`outputType: '${selectedOutputType}'`] : []),
302
+ ];
303
+ const targetCode = `angularOutputTarget({\n ${lines.join(',\n ')},\n})`;
304
+ // Amend stencil.config.ts in one pass so formatText() sees the final array
305
+ try {
306
+ const added = amendStencilConfig(stencilConfigPath, targetCode);
307
+ log.success(added ? 'stencil.config.ts updated' : 'angularOutputTarget already present — no changes made');
308
+ }
309
+ catch (e) {
310
+ log.warn(`Could not automatically update stencil.config.ts (${e}). Add manually:\n\n` +
311
+ `import { angularOutputTarget } from '@stencil/angular-output-target';\n` +
312
+ `// in outputTargets:\n${targetCode}`);
313
+ }
314
+ // Install @stencil/angular-output-target as a devDep of the core package
315
+ log.info('Installing @stencil/angular-output-target...');
316
+ await nypm.addDependency(['@stencil/angular-output-target'], { cwd: config.rootDir, dev: true });
317
+ log.success('Installed @stencil/angular-output-target');
318
+ if (shouldScaffold && (await pathExists(wrapperDir))) {
319
+ log.info('Installing Angular dependencies in wrapper package...');
320
+ await nypm.addDependency([
321
+ '@angular/core',
322
+ '@angular/common',
323
+ '@angular/compiler',
324
+ '@angular/compiler-cli',
325
+ 'ng-packagr',
326
+ 'rxjs',
327
+ 'tslib',
328
+ ], { cwd: wrapperDir, dev: true });
329
+ log.success('Angular dependencies installed');
330
+ }
331
+ outro('Angular output target configured');
332
+ },
333
+ },
334
+ };
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "@stencil/angular-output-target",
3
- "version": "1.3.2",
3
+ "version": "1.4.0",
4
4
  "description": "Angular output target for @stencil/core components.",
5
- "main": "dist/index.cjs.js",
5
+ "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",
7
+ "type": "module",
8
+ "stencil": {
9
+ "wizard": "./dist/wizard.js"
10
+ },
7
11
  "exports": {
8
12
  ".": {
9
13
  "types": "./dist/index.d.ts",
10
14
  "import": "./dist/index.js",
11
- "require": "./dist/index.cjs.js"
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./wizard": {
18
+ "types": "./dist/wizard.d.ts",
19
+ "import": "./dist/wizard.js"
12
20
  }
13
21
  },
14
22
  "types": "dist/index.d.ts",
@@ -47,7 +55,11 @@
47
55
  "bugs": {
48
56
  "url": "https://github.com/stenciljs/output-targets/issues"
49
57
  },
58
+ "dependencies": {
59
+ "ts-morph": "^28.0.0"
60
+ },
50
61
  "devDependencies": {
62
+ "@stencil/cli": "^5.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0",
51
63
  "@angular/core": "8.2.14",
52
64
  "@angular/forms": "8.2.14",
53
65
  "@stencil/core": "4.41.0",
@@ -59,7 +71,7 @@
59
71
  "vitest": "^2.1.4"
60
72
  },
61
73
  "peerDependencies": {
62
- "@stencil/core": ">=2.0.0 || >=3 || >= 4.0.0-beta.0 || >= 4.0.0"
74
+ "@stencil/core": ">=2.0.0 || >=3 || >=4.0.0 || ^5.0.0 || >=5.0.0-alpha.0 <5.0.0-next.0"
63
75
  },
64
76
  "gitHead": "a3588e905186a0e86e7f88418fd5b2f9531b55e0"
65
77
  }