@c15t/cli 1.4.4 → 1.5.0-canary-20250722085128
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/index.mjs +318 -34
- package/dist/onboarding/templates/index.d.ts +7 -0
- package/dist/onboarding/templates/index.d.ts.map +1 -0
- package/dist/onboarding/templates/layout.d.ts +3 -11
- package/dist/onboarding/templates/layout.d.ts.map +1 -1
- package/dist/onboarding/templates/next/app/layout.d.ts +20 -0
- package/dist/onboarding/templates/next/app/layout.d.ts.map +1 -0
- package/dist/onboarding/templates/next/index.d.ts +23 -0
- package/dist/onboarding/templates/next/index.d.ts.map +1 -0
- package/dist/onboarding/templates/next/pages/layout.d.ts +20 -0
- package/dist/onboarding/templates/next/pages/layout.d.ts.map +1 -0
- package/dist/onboarding/templates/shared/options.d.ts +37 -0
- package/dist/onboarding/templates/shared/options.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -779,26 +779,6 @@ function generateEnvExampleContent(pkg) {
|
|
|
779
779
|
const envVarName = getEnvVarName(pkg);
|
|
780
780
|
return `\n# c15t Configuration\n${envVarName}=https://your-instance.c15t.dev\n`;
|
|
781
781
|
}
|
|
782
|
-
const HTML_TAG_REGEX = /<html[^>]*>([\s\S]*)<\/html>/;
|
|
783
|
-
const BODY_TAG_REGEX = /<body[^>]*>([\s\S]*)<\/body>/;
|
|
784
|
-
const BODY_OPENING_TAG_REGEX = /<body[^>]*>/;
|
|
785
|
-
const HTML_CONTENT_REGEX = /([\s\S]*<\/html>)/;
|
|
786
|
-
function findLayoutFile(project, projectRoot) {
|
|
787
|
-
const layoutPatterns = [
|
|
788
|
-
'**/app.tsx',
|
|
789
|
-
'**/App.tsx',
|
|
790
|
-
'**/app/app.tsx',
|
|
791
|
-
'**/src/app/app.tsx',
|
|
792
|
-
'**/layout.tsx',
|
|
793
|
-
'**/Layout.tsx',
|
|
794
|
-
'**/app/layout.tsx',
|
|
795
|
-
'**/src/app/layout.tsx'
|
|
796
|
-
];
|
|
797
|
-
for (const pattern of layoutPatterns){
|
|
798
|
-
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
799
|
-
if (files.length > 0) return files[0];
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
782
|
function generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs) {
|
|
803
783
|
switch(mode){
|
|
804
784
|
case 'c15t':
|
|
@@ -832,12 +812,43 @@ function generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs) {
|
|
|
832
812
|
}`;
|
|
833
813
|
}
|
|
834
814
|
}
|
|
835
|
-
function
|
|
836
|
-
|
|
837
|
-
'ConsentManagerProvider',
|
|
815
|
+
function getBaseImports() {
|
|
816
|
+
return [
|
|
838
817
|
'CookieBanner',
|
|
839
818
|
'ConsentManagerDialog'
|
|
840
819
|
];
|
|
820
|
+
}
|
|
821
|
+
function getCustomModeImports() {
|
|
822
|
+
return [
|
|
823
|
+
{
|
|
824
|
+
namedImports: [
|
|
825
|
+
'createCustomHandlers'
|
|
826
|
+
],
|
|
827
|
+
moduleSpecifier: './consent-handlers'
|
|
828
|
+
}
|
|
829
|
+
];
|
|
830
|
+
}
|
|
831
|
+
const HTML_TAG_REGEX = /<html[^>]*>([\s\S]*)<\/html>/;
|
|
832
|
+
const BODY_TAG_REGEX = /<body[^>]*>([\s\S]*)<\/body>/;
|
|
833
|
+
const BODY_OPENING_TAG_REGEX = /<body[^>]*>/;
|
|
834
|
+
const HTML_CONTENT_REGEX = /([\s\S]*<\/html>)/;
|
|
835
|
+
function findAppLayoutFile(project, projectRoot) {
|
|
836
|
+
const layoutPatterns = [
|
|
837
|
+
'app/layout.tsx',
|
|
838
|
+
'src/app/layout.tsx',
|
|
839
|
+
'app/layout.ts',
|
|
840
|
+
'src/app/layout.ts'
|
|
841
|
+
];
|
|
842
|
+
for (const pattern of layoutPatterns){
|
|
843
|
+
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
844
|
+
if (files.length > 0) return files[0];
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
function updateAppImports(layoutFile, packageName, mode) {
|
|
848
|
+
const requiredImports = [
|
|
849
|
+
'ConsentManagerProvider',
|
|
850
|
+
...getBaseImports()
|
|
851
|
+
];
|
|
841
852
|
let hasC15tImport = false;
|
|
842
853
|
for (const importDecl of layoutFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === packageName) {
|
|
843
854
|
hasC15tImport = true;
|
|
@@ -850,14 +861,9 @@ function updateImports(layoutFile, packageName, mode) {
|
|
|
850
861
|
namedImports: requiredImports,
|
|
851
862
|
moduleSpecifier: packageName
|
|
852
863
|
});
|
|
853
|
-
if ('custom' === mode) layoutFile.addImportDeclaration(
|
|
854
|
-
namedImports: [
|
|
855
|
-
'createCustomHandlers'
|
|
856
|
-
],
|
|
857
|
-
moduleSpecifier: './consent-handlers'
|
|
858
|
-
});
|
|
864
|
+
if ('custom' === mode) for (const customImport of getCustomModeImports())layoutFile.addImportDeclaration(customImport);
|
|
859
865
|
}
|
|
860
|
-
function
|
|
866
|
+
function wrapAppJsxContent(originalJsx, optionsText) {
|
|
861
867
|
const hasHtmlTag = originalJsx.includes('<html') || originalJsx.includes('</html>');
|
|
862
868
|
const hasBodyTag = originalJsx.includes('<body') || originalJsx.includes('</body>');
|
|
863
869
|
const providerWrapper = (content)=>`
|
|
@@ -886,9 +892,9 @@ function wrapJsxContent(originalJsx, optionsText) {
|
|
|
886
892
|
}
|
|
887
893
|
return providerWrapper(originalJsx);
|
|
888
894
|
}
|
|
889
|
-
async function
|
|
895
|
+
async function updateAppLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
|
|
890
896
|
const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
|
|
891
|
-
const layoutFile =
|
|
897
|
+
const layoutFile = findAppLayoutFile(project, projectRoot);
|
|
892
898
|
if (!layoutFile) return {
|
|
893
899
|
updated: false,
|
|
894
900
|
filePath: null,
|
|
@@ -901,7 +907,7 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
|
|
|
901
907
|
filePath: layoutFile.getFilePath(),
|
|
902
908
|
alreadyModified: true
|
|
903
909
|
};
|
|
904
|
-
|
|
910
|
+
updateAppImports(layoutFile, pkg, mode);
|
|
905
911
|
const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
|
|
906
912
|
const returnStatement = layoutFile.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
|
|
907
913
|
if (!returnStatement) return {
|
|
@@ -916,7 +922,7 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
|
|
|
916
922
|
alreadyModified: false
|
|
917
923
|
};
|
|
918
924
|
const originalJsx = expression.getText();
|
|
919
|
-
const newJsx =
|
|
925
|
+
const newJsx = wrapAppJsxContent(originalJsx, optionsText);
|
|
920
926
|
returnStatement.replaceWithText(`return ${newJsx}`);
|
|
921
927
|
await layoutFile.save();
|
|
922
928
|
return {
|
|
@@ -925,6 +931,284 @@ async function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFil
|
|
|
925
931
|
alreadyModified: false
|
|
926
932
|
};
|
|
927
933
|
}
|
|
934
|
+
function findPagesAppFile(project, projectRoot) {
|
|
935
|
+
const appPatterns = [
|
|
936
|
+
'pages/_app.tsx',
|
|
937
|
+
'pages/_app.ts',
|
|
938
|
+
'src/pages/_app.tsx',
|
|
939
|
+
'src/pages/_app.ts'
|
|
940
|
+
];
|
|
941
|
+
for (const pattern of appPatterns){
|
|
942
|
+
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
943
|
+
if (files.length > 0) return files[0];
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
function updatePagesImports(appFile, packageName, mode) {
|
|
947
|
+
const requiredImports = [
|
|
948
|
+
'ConsentManagerProvider',
|
|
949
|
+
...getBaseImports()
|
|
950
|
+
];
|
|
951
|
+
const pagesModuleSpecifier = `${packageName}/pages`;
|
|
952
|
+
let hasC15tImport = false;
|
|
953
|
+
for (const importDecl of appFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === pagesModuleSpecifier) {
|
|
954
|
+
hasC15tImport = true;
|
|
955
|
+
const namedImports = importDecl.getNamedImports().map((i)=>i.getName());
|
|
956
|
+
const missingImports = requiredImports.filter((imp)=>!namedImports.includes(imp));
|
|
957
|
+
if (missingImports.length > 0) importDecl.addNamedImports(missingImports);
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
if (!hasC15tImport) appFile.addImportDeclaration({
|
|
961
|
+
namedImports: requiredImports,
|
|
962
|
+
moduleSpecifier: pagesModuleSpecifier
|
|
963
|
+
});
|
|
964
|
+
if ('custom' === mode) for (const customImport of getCustomModeImports())appFile.addImportDeclaration(customImport);
|
|
965
|
+
}
|
|
966
|
+
function wrapPagesJsxContent(originalJsx, optionsText) {
|
|
967
|
+
const trimmedJsx = originalJsx.trim();
|
|
968
|
+
const hasParentheses = trimmedJsx.startsWith('(') && trimmedJsx.endsWith(')');
|
|
969
|
+
const cleanJsx = hasParentheses ? trimmedJsx.slice(1, -1).trim() : originalJsx;
|
|
970
|
+
const wrappedContent = `
|
|
971
|
+
<ConsentManagerProvider
|
|
972
|
+
initialData={pageProps.initialC15TData}
|
|
973
|
+
options={${optionsText}}
|
|
974
|
+
>
|
|
975
|
+
<CookieBanner />
|
|
976
|
+
<ConsentManagerDialog />
|
|
977
|
+
${cleanJsx}
|
|
978
|
+
</ConsentManagerProvider>
|
|
979
|
+
`;
|
|
980
|
+
return `(${wrappedContent})`;
|
|
981
|
+
}
|
|
982
|
+
function addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs) {
|
|
983
|
+
const existingComments = appFile.getLeadingCommentRanges();
|
|
984
|
+
let urlExample;
|
|
985
|
+
urlExample = proxyNextjs ? "'/api/c15t'" : useEnvFile ? 'process.env.NEXT_PUBLIC_C15T_URL!' : `'${backendURL || 'https://your-instance.c15t.dev'}'`;
|
|
986
|
+
const serverSideComment = `/**
|
|
987
|
+
* Note: To get the initial server-side data on other pages, add this to each page:
|
|
988
|
+
*
|
|
989
|
+
* import { withInitialC15TData } from '@c15t/nextjs/pages';
|
|
990
|
+
*
|
|
991
|
+
* export const getServerSideProps = withInitialC15TData(${urlExample});
|
|
992
|
+
*
|
|
993
|
+
* This will automatically pass initialC15TData to pageProps.initialC15TData
|
|
994
|
+
*/`;
|
|
995
|
+
const hasServerSideComment = existingComments.some((comment)=>comment.getText().includes('withInitialC15TData'));
|
|
996
|
+
if (!hasServerSideComment) appFile.insertText(0, `${serverSideComment}\n\n`);
|
|
997
|
+
}
|
|
998
|
+
function updateAppComponentTyping(appFile) {
|
|
999
|
+
const exportAssignment = appFile.getExportAssignment(()=>true);
|
|
1000
|
+
if (!exportAssignment) return;
|
|
1001
|
+
const declaration = exportAssignment.getExpression();
|
|
1002
|
+
if (!declaration) return;
|
|
1003
|
+
const text = declaration.getText();
|
|
1004
|
+
if (text.includes('pageProps') && !text.includes('AppProps')) {
|
|
1005
|
+
const hasAppPropsImport = appFile.getImportDeclarations().some((importDecl)=>'next/app' === importDecl.getModuleSpecifierValue() && importDecl.getNamedImports().some((namedImport)=>'AppProps' === namedImport.getName()));
|
|
1006
|
+
if (!hasAppPropsImport) appFile.addImportDeclaration({
|
|
1007
|
+
namedImports: [
|
|
1008
|
+
'AppProps'
|
|
1009
|
+
],
|
|
1010
|
+
moduleSpecifier: 'next/app'
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
async function updatePagesLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
|
|
1015
|
+
const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
|
|
1016
|
+
const appFile = findPagesAppFile(project, projectRoot);
|
|
1017
|
+
if (!appFile) return {
|
|
1018
|
+
updated: false,
|
|
1019
|
+
filePath: null,
|
|
1020
|
+
alreadyModified: false
|
|
1021
|
+
};
|
|
1022
|
+
const existingImports = appFile.getImportDeclarations();
|
|
1023
|
+
const pagesModuleSpecifier = `${pkg}/pages`;
|
|
1024
|
+
const hasPackageImport = existingImports.some((importDecl)=>importDecl.getModuleSpecifierValue() === pagesModuleSpecifier);
|
|
1025
|
+
if (hasPackageImport) return {
|
|
1026
|
+
updated: false,
|
|
1027
|
+
filePath: appFile.getFilePath(),
|
|
1028
|
+
alreadyModified: true
|
|
1029
|
+
};
|
|
1030
|
+
updatePagesImports(appFile, pkg, mode);
|
|
1031
|
+
updateAppComponentTyping(appFile);
|
|
1032
|
+
addServerSideDataComment(appFile, backendURL, useEnvFile, proxyNextjs);
|
|
1033
|
+
const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
|
|
1034
|
+
const returnStatement = appFile.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
|
|
1035
|
+
if (!returnStatement) return {
|
|
1036
|
+
updated: false,
|
|
1037
|
+
filePath: appFile.getFilePath(),
|
|
1038
|
+
alreadyModified: false
|
|
1039
|
+
};
|
|
1040
|
+
const expression = returnStatement.getExpression();
|
|
1041
|
+
if (!expression) return {
|
|
1042
|
+
updated: false,
|
|
1043
|
+
filePath: appFile.getFilePath(),
|
|
1044
|
+
alreadyModified: false
|
|
1045
|
+
};
|
|
1046
|
+
const originalJsx = expression.getText();
|
|
1047
|
+
const newJsx = wrapPagesJsxContent(originalJsx, optionsText);
|
|
1048
|
+
returnStatement.replaceWithText(`return ${newJsx}`);
|
|
1049
|
+
await appFile.save();
|
|
1050
|
+
return {
|
|
1051
|
+
updated: true,
|
|
1052
|
+
filePath: appFile.getFilePath(),
|
|
1053
|
+
alreadyModified: false
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
function detectNextJsStructure(projectRoot) {
|
|
1057
|
+
const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
|
|
1058
|
+
const appLayoutPatterns = [
|
|
1059
|
+
'app/layout.tsx',
|
|
1060
|
+
'src/app/layout.tsx',
|
|
1061
|
+
'app/layout.ts',
|
|
1062
|
+
'src/app/layout.ts'
|
|
1063
|
+
];
|
|
1064
|
+
for (const pattern of appLayoutPatterns){
|
|
1065
|
+
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
1066
|
+
if (files.length > 0) return 'app';
|
|
1067
|
+
}
|
|
1068
|
+
const pagesAppPatterns = [
|
|
1069
|
+
'pages/_app.tsx',
|
|
1070
|
+
'pages/_app.ts',
|
|
1071
|
+
'src/pages/_app.tsx',
|
|
1072
|
+
'src/pages/_app.ts'
|
|
1073
|
+
];
|
|
1074
|
+
for (const pattern of pagesAppPatterns){
|
|
1075
|
+
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
1076
|
+
if (files.length > 0) return 'pages';
|
|
1077
|
+
}
|
|
1078
|
+
return null;
|
|
1079
|
+
}
|
|
1080
|
+
async function updateNextLayout(options) {
|
|
1081
|
+
const structureType = detectNextJsStructure(options.projectRoot);
|
|
1082
|
+
if (!structureType) return {
|
|
1083
|
+
updated: false,
|
|
1084
|
+
filePath: null,
|
|
1085
|
+
alreadyModified: false,
|
|
1086
|
+
structureType: null
|
|
1087
|
+
};
|
|
1088
|
+
let result;
|
|
1089
|
+
result = 'app' === structureType ? await updateAppLayout(options) : await updatePagesLayout(options);
|
|
1090
|
+
return {
|
|
1091
|
+
...result,
|
|
1092
|
+
structureType
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
function updateGenericReactImports(layoutFile, packageName, mode) {
|
|
1096
|
+
const requiredImports = [
|
|
1097
|
+
'ConsentManagerProvider',
|
|
1098
|
+
...getBaseImports()
|
|
1099
|
+
];
|
|
1100
|
+
let hasPackageImport = false;
|
|
1101
|
+
for (const importDecl of layoutFile.getImportDeclarations())if (importDecl.getModuleSpecifierValue() === packageName) {
|
|
1102
|
+
hasPackageImport = true;
|
|
1103
|
+
const namedImports = importDecl.getNamedImports().map((i)=>i.getName());
|
|
1104
|
+
const missingImports = requiredImports.filter((imp)=>!namedImports.includes(imp));
|
|
1105
|
+
if (missingImports.length > 0) importDecl.addNamedImports(missingImports);
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
if (!hasPackageImport) layoutFile.addImportDeclaration({
|
|
1109
|
+
namedImports: requiredImports,
|
|
1110
|
+
moduleSpecifier: packageName
|
|
1111
|
+
});
|
|
1112
|
+
if ('custom' === mode) for (const customImport of getCustomModeImports())layoutFile.addImportDeclaration(customImport);
|
|
1113
|
+
}
|
|
1114
|
+
function updateGenericReactJsx(layoutFile, mode, backendURL, useEnvFile, proxyNextjs) {
|
|
1115
|
+
const functionDeclarations = layoutFile.getFunctions();
|
|
1116
|
+
const variableDeclarations = layoutFile.getVariableDeclarations();
|
|
1117
|
+
for (const func of functionDeclarations){
|
|
1118
|
+
const returnStatement = func.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
|
|
1119
|
+
if (returnStatement) return wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs);
|
|
1120
|
+
}
|
|
1121
|
+
for (const varDecl of variableDeclarations){
|
|
1122
|
+
const initializer = varDecl.getInitializer();
|
|
1123
|
+
if (initializer) {
|
|
1124
|
+
const returnStatement = initializer.getDescendantsOfKind(__WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.SyntaxKind.ReturnStatement)[0];
|
|
1125
|
+
if (returnStatement) return wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
return false;
|
|
1129
|
+
}
|
|
1130
|
+
function wrapReturnStatement(returnStatement, mode, backendURL, useEnvFile, proxyNextjs) {
|
|
1131
|
+
const expression = returnStatement.getExpression();
|
|
1132
|
+
if (!expression) return false;
|
|
1133
|
+
const originalJsx = expression.getText();
|
|
1134
|
+
const optionsText = generateOptionsText(mode, backendURL, useEnvFile, proxyNextjs);
|
|
1135
|
+
const newJsx = `(
|
|
1136
|
+
<ConsentManagerProvider options={${optionsText}}>
|
|
1137
|
+
<CookieBanner />
|
|
1138
|
+
<ConsentManagerDialog />
|
|
1139
|
+
${originalJsx}
|
|
1140
|
+
</ConsentManagerProvider>
|
|
1141
|
+
)`;
|
|
1142
|
+
returnStatement.replaceWithText(`return ${newJsx}`);
|
|
1143
|
+
return true;
|
|
1144
|
+
}
|
|
1145
|
+
async function updateGenericReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs }) {
|
|
1146
|
+
const layoutPatterns = [
|
|
1147
|
+
'app.tsx',
|
|
1148
|
+
'App.tsx',
|
|
1149
|
+
'app.jsx',
|
|
1150
|
+
'App.jsx',
|
|
1151
|
+
'src/app.tsx',
|
|
1152
|
+
'src/App.tsx',
|
|
1153
|
+
'src/app.jsx',
|
|
1154
|
+
'src/App.jsx',
|
|
1155
|
+
'src/app/app.tsx',
|
|
1156
|
+
'src/app/App.tsx',
|
|
1157
|
+
'src/app/app.jsx',
|
|
1158
|
+
'src/app/App.jsx'
|
|
1159
|
+
];
|
|
1160
|
+
const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
|
|
1161
|
+
let layoutFile;
|
|
1162
|
+
for (const pattern of layoutPatterns)try {
|
|
1163
|
+
const files = project.addSourceFilesAtPaths(`${projectRoot}/${pattern}`);
|
|
1164
|
+
if (files.length > 0) {
|
|
1165
|
+
layoutFile = files[0];
|
|
1166
|
+
break;
|
|
1167
|
+
}
|
|
1168
|
+
} catch {}
|
|
1169
|
+
if (!layoutFile) return {
|
|
1170
|
+
updated: false,
|
|
1171
|
+
filePath: null,
|
|
1172
|
+
alreadyModified: false
|
|
1173
|
+
};
|
|
1174
|
+
const existingImports = layoutFile.getImportDeclarations();
|
|
1175
|
+
const hasPackageImport = existingImports.some((importDecl)=>importDecl.getModuleSpecifierValue() === pkg);
|
|
1176
|
+
if (hasPackageImport) return {
|
|
1177
|
+
updated: false,
|
|
1178
|
+
filePath: layoutFile.getFilePath(),
|
|
1179
|
+
alreadyModified: true
|
|
1180
|
+
};
|
|
1181
|
+
try {
|
|
1182
|
+
updateGenericReactImports(layoutFile, pkg, mode);
|
|
1183
|
+
const updated = updateGenericReactJsx(layoutFile, mode, backendURL, useEnvFile, proxyNextjs);
|
|
1184
|
+
if (updated) {
|
|
1185
|
+
await layoutFile.save();
|
|
1186
|
+
return {
|
|
1187
|
+
updated: true,
|
|
1188
|
+
filePath: layoutFile.getFilePath(),
|
|
1189
|
+
alreadyModified: false
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
return {
|
|
1193
|
+
updated: false,
|
|
1194
|
+
filePath: layoutFile.getFilePath(),
|
|
1195
|
+
alreadyModified: false
|
|
1196
|
+
};
|
|
1197
|
+
} catch (error) {
|
|
1198
|
+
throw new Error(`Failed to update generic React layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
async function updateReactLayout(options) {
|
|
1202
|
+
if ('@c15t/nextjs' === options.pkg) {
|
|
1203
|
+
const nextResult = await updateNextLayout(options);
|
|
1204
|
+
if (nextResult.structureType) return {
|
|
1205
|
+
updated: nextResult.updated,
|
|
1206
|
+
filePath: nextResult.filePath,
|
|
1207
|
+
alreadyModified: nextResult.alreadyModified
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
return updateGenericReactLayout(options);
|
|
1211
|
+
}
|
|
928
1212
|
async function updateNextConfig({ projectRoot, backendURL, useEnvFile }) {
|
|
929
1213
|
const project = new __WEBPACK_EXTERNAL_MODULE_ts_morph_07c7ce60__.Project();
|
|
930
1214
|
const configFile = findNextConfigFile(project, projectRoot);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { updateReactLayout } from './layout';
|
|
2
|
+
export { updateNextLayout } from './next';
|
|
3
|
+
export { updateAppLayout } from './next/app/layout';
|
|
4
|
+
export { updatePagesLayout } from './next/pages/layout';
|
|
5
|
+
export { generateOptionsText, getBaseImports, getCustomModeImports, } from './shared/options';
|
|
6
|
+
export type { AvailablePackages } from '../../context/framework-detection';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EACN,mBAAmB,EACnB,cAAc,EACd,oBAAoB,GACpB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Templates module for generating configuration files
|
|
3
|
-
*
|
|
3
|
+
* This module now serves as a wrapper that routes to the appropriate implementation
|
|
4
|
+
* based on the detected project structure (App Directory vs Pages Directory)
|
|
4
5
|
*/
|
|
5
6
|
import type { AvailablePackages } from '../../context/framework-detection';
|
|
6
7
|
interface UpdateReactLayoutOptions {
|
|
@@ -11,16 +12,7 @@ interface UpdateReactLayoutOptions {
|
|
|
11
12
|
pkg: AvailablePackages;
|
|
12
13
|
proxyNextjs?: boolean;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
-
* Updates or creates a React layout file with ConsentManagerProvider
|
|
16
|
-
*
|
|
17
|
-
* @param projectRoot - The root directory of the project
|
|
18
|
-
* @param mode - The storage mode ('c15t', 'offline', or 'custom')
|
|
19
|
-
* @param backendURL - URL for the c15t backend/API (for 'c15t' mode)
|
|
20
|
-
* @param useEnvFile - Whether to use environment variable for backendURL
|
|
21
|
-
* @returns Information about the update
|
|
22
|
-
*/
|
|
23
|
-
export declare function updateReactLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdateReactLayoutOptions): Promise<{
|
|
15
|
+
export declare function updateReactLayout(options: UpdateReactLayoutOptions): Promise<{
|
|
24
16
|
updated: boolean;
|
|
25
17
|
filePath: string | null;
|
|
26
18
|
alreadyModified: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/layout.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/onboarding/templates/layout.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAQvE,UAAU,wBAAwB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAwQD,wBAAsB,iBAAiB,CACtC,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CAiBD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Directory layout template generator
|
|
3
|
+
* Handles updating Next.js App Directory layout files with ConsentManagerProvider
|
|
4
|
+
*/
|
|
5
|
+
import type { AvailablePackages } from '../../../../context/framework-detection';
|
|
6
|
+
interface UpdateAppLayoutOptions {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
mode: string;
|
|
9
|
+
backendURL?: string;
|
|
10
|
+
useEnvFile?: boolean;
|
|
11
|
+
pkg: AvailablePackages;
|
|
12
|
+
proxyNextjs?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function updateAppLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdateAppLayoutOptions): Promise<{
|
|
15
|
+
updated: boolean;
|
|
16
|
+
filePath: string | null;
|
|
17
|
+
alreadyModified: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/onboarding/templates/next/app/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAYvE,UAAU,sBAAsB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAkHD,wBAAsB,eAAe,CAAC,EACrC,WAAW,EACX,IAAI,EACJ,GAAG,EACH,UAAU,EACV,UAAU,EACV,WAAW,GACX,EAAE,sBAAsB,GAAG,OAAO,CAAC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CA2DD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Next.js template handler
|
|
3
|
+
* Detects whether the project uses App Directory or Pages Directory
|
|
4
|
+
* and routes to the appropriate implementation
|
|
5
|
+
*/
|
|
6
|
+
import type { AvailablePackages } from '../../../context/framework-detection';
|
|
7
|
+
interface UpdateNextLayoutOptions {
|
|
8
|
+
projectRoot: string;
|
|
9
|
+
mode: string;
|
|
10
|
+
backendURL?: string;
|
|
11
|
+
useEnvFile?: boolean;
|
|
12
|
+
pkg: AvailablePackages;
|
|
13
|
+
proxyNextjs?: boolean;
|
|
14
|
+
}
|
|
15
|
+
type NextStructure = 'app' | 'pages' | null;
|
|
16
|
+
export declare function updateNextLayout(options: UpdateNextLayoutOptions): Promise<{
|
|
17
|
+
updated: boolean;
|
|
18
|
+
filePath: string | null;
|
|
19
|
+
alreadyModified: boolean;
|
|
20
|
+
structureType: NextStructure;
|
|
21
|
+
}>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/onboarding/templates/next/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIvE,UAAU,uBAAuB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,KAAK,aAAa,GAAG,KAAK,GAAG,OAAO,GAAG,IAAI,CAAC;AAsC5C,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC;IACV,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC7B,CAAC,CA4BD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pages Directory layout template generator
|
|
3
|
+
* Handles updating Next.js Pages Directory _app.tsx files with ConsentManagerProvider
|
|
4
|
+
*/
|
|
5
|
+
import type { AvailablePackages } from '../../../../context/framework-detection';
|
|
6
|
+
interface UpdatePagesLayoutOptions {
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
mode: string;
|
|
9
|
+
backendURL?: string;
|
|
10
|
+
useEnvFile?: boolean;
|
|
11
|
+
pkg: AvailablePackages;
|
|
12
|
+
proxyNextjs?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function updatePagesLayout({ projectRoot, mode, pkg, backendURL, useEnvFile, proxyNextjs, }: UpdatePagesLayoutOptions): Promise<{
|
|
15
|
+
updated: boolean;
|
|
16
|
+
filePath: string | null;
|
|
17
|
+
alreadyModified: boolean;
|
|
18
|
+
}>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/onboarding/templates/next/pages/layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,UAAU,wBAAwB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,iBAAiB,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAyJD,wBAAsB,iBAAiB,CAAC,EACvC,WAAW,EACX,IAAI,EACJ,GAAG,EACH,UAAU,EACV,UAAU,EACV,WAAW,GACX,EAAE,wBAAwB,GAAG,OAAO,CAAC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC,CAgED"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared template configuration generators
|
|
3
|
+
* These functions generate template configuration content for different storage modes
|
|
4
|
+
* Used by both App Directory and Pages Directory implementations
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generates the options text for ConsentManagerProvider based on mode and configuration
|
|
8
|
+
*
|
|
9
|
+
* @param mode - The storage mode ('c15t', 'offline', or 'custom')
|
|
10
|
+
* @param backendURL - URL for the c15t backend/API (for 'c15t' mode)
|
|
11
|
+
* @param useEnvFile - Whether to use environment variable for backendURL
|
|
12
|
+
* @param proxyNextjs - Whether to use Next.js API proxy for c15t mode
|
|
13
|
+
* @returns The formatted options object as a string
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* const options = generateOptionsText('c15t', 'https://api.example.com', false, true);
|
|
18
|
+
* // Returns: "{ mode: 'c15t', backendURL: '/api/c15t', ... }"
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateOptionsText(mode: string, backendURL?: string, useEnvFile?: boolean, proxyNextjs?: boolean): string;
|
|
22
|
+
/**
|
|
23
|
+
* Gets the required base imports for ConsentManagerProvider
|
|
24
|
+
*
|
|
25
|
+
* @returns Array of import names needed for basic consent management
|
|
26
|
+
*/
|
|
27
|
+
export declare function getBaseImports(): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Gets additional imports needed for custom mode
|
|
30
|
+
*
|
|
31
|
+
* @returns Array of import configurations for custom handlers
|
|
32
|
+
*/
|
|
33
|
+
export declare function getCustomModeImports(): Array<{
|
|
34
|
+
namedImports: string[];
|
|
35
|
+
moduleSpecifier: string;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../../src/onboarding/templates/shared/options.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAClC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,OAAO,EACpB,WAAW,CAAC,EAAE,OAAO,GACnB,MAAM,CAuCR;AAED;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,MAAM,EAAE,CAEzC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAC7C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACxB,CAAC,CAOD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@c15t/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0-canary-20250722085128",
|
|
4
4
|
"description": "The CLI for c15t",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./dist/index.mjs",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"posthog-node": "^4.11.7",
|
|
30
30
|
"ts-morph": "^25.0.1",
|
|
31
31
|
"zod": "^3.24.2",
|
|
32
|
-
"@c15t/backend": "1.
|
|
33
|
-
"@c15t/react": "1.
|
|
32
|
+
"@c15t/backend": "1.5.0-canary-20250722085128",
|
|
33
|
+
"@c15t/react": "1.5.0-canary-20250722085128"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/figlet": "^1.7.0",
|