@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.
- package/dist/generate-value-accessors.js +8 -2
- package/dist/{index.cjs.js → index.cjs} +55 -34
- package/dist/index.js +54 -33
- package/dist/output-angular.d.ts +3 -2
- package/dist/output-angular.js +37 -25
- package/dist/plugin.js +7 -2
- package/dist/utils.js +1 -2
- package/dist/wizard.d.ts +9 -0
- package/dist/wizard.js +334 -0
- package/package.json +16 -4
|
@@ -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
|
|
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
|
|
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
|
|
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
|
-
|
|
891
|
-
?
|
|
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
|
-
|
|
916
|
-
|
|
917
|
-
|
|
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 =
|
|
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
|
-
|
|
985
|
-
|
|
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
|
-
|
|
996
|
-
|
|
997
|
-
|
|
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
|
-
|
|
1066
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
883
|
-
?
|
|
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
|
-
|
|
908
|
-
|
|
909
|
-
|
|
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 =
|
|
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
|
-
|
|
977
|
-
|
|
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
|
-
|
|
988
|
-
|
|
989
|
-
|
|
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
|
-
|
|
1058
|
-
|
|
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
|
}
|
package/dist/output-angular.d.ts
CHANGED
|
@@ -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;
|
package/dist/output-angular.js
CHANGED
|
@@ -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
|
-
|
|
121
|
-
?
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 =
|
|
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
|
-
|
|
215
|
-
|
|
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
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
|
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}`);
|
package/dist/wizard.d.ts
ADDED
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
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Angular output target for @stencil/core components.",
|
|
5
|
-
"main": "dist/index.cjs
|
|
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
|
|
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 || >=
|
|
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
|
}
|