@slicemachine/init 1.1.9 → 1.1.10-alpha.1

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/build/index.js CHANGED
@@ -23,6 +23,15 @@ const tmp = require('tmp');
23
23
  const AdmZip = require('adm-zip');
24
24
  const fsExtra = require('fs-extra');
25
25
  const fs = require('fs');
26
+ const cookie = require('@slicemachine/core/build/utils/cookie');
27
+ const Libraries = require('@slicemachine/core/build/libraries');
28
+ const models = require('@slicemachine/core/build/models');
29
+ const mime = require('mime');
30
+ const snakeCase = require('lodash.snakecase');
31
+ const FormData = require('form-data');
32
+ const uniqid = require('uniqid');
33
+ const customtypes = require('@prismicio/types-internal/lib/customtypes');
34
+ const Either$1 = require('fp-ts/lib/Either');
26
35
 
27
36
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
28
37
 
@@ -55,12 +64,18 @@ const hapi__namespace = /*#__PURE__*/_interopNamespace(hapi);
55
64
  const open__default = /*#__PURE__*/_interopDefaultLegacy(open);
56
65
  const NodeUtils__namespace = /*#__PURE__*/_interopNamespace(NodeUtils);
57
66
  const inquirer__namespace = /*#__PURE__*/_interopNamespace(inquirer);
67
+ const inquirer__default = /*#__PURE__*/_interopDefaultLegacy(inquirer);
58
68
  const Separator__default = /*#__PURE__*/_interopDefaultLegacy(Separator);
59
69
  const axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
60
70
  const tmp__default = /*#__PURE__*/_interopDefaultLegacy(tmp);
61
71
  const AdmZip__default = /*#__PURE__*/_interopDefaultLegacy(AdmZip);
62
72
  const fsExtra__default = /*#__PURE__*/_interopDefaultLegacy(fsExtra);
63
73
  const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
74
+ const Libraries__namespace = /*#__PURE__*/_interopNamespace(Libraries);
75
+ const mime__default = /*#__PURE__*/_interopDefaultLegacy(mime);
76
+ const snakeCase__default = /*#__PURE__*/_interopDefaultLegacy(snakeCase);
77
+ const FormData__default = /*#__PURE__*/_interopDefaultLegacy(FormData);
78
+ const uniqid__default = /*#__PURE__*/_interopDefaultLegacy(uniqid);
64
79
 
65
80
  var __accessCheck = (obj, member, msg) => {
66
81
  if (!member.has(obj))
@@ -403,16 +418,25 @@ function depsForFramework(framework) {
403
418
  return "";
404
419
  }
405
420
  }
406
- async function installRequiredDependencies(cwd, framework) {
407
- const yarnLock = NodeUtils__namespace.Files.exists(NodeUtils__namespace.YarnLockPath(cwd));
408
- const installDevDependencyCommand = yarnLock ? "yarn add -D" : "npm install --save-dev";
409
- const installDependencyCommand = yarnLock ? "yarn add" : "npm install --save";
410
- const spinner = spinner$1("Downloading Slice Machine");
411
- spinner.start();
421
+ async function addAndInstallDeps(framework, useYarn = false) {
422
+ const installDevDependencyCommand = useYarn ? "yarn add -D" : "npm install --save-dev";
423
+ const installDependencyCommand = useYarn ? "yarn add" : "npm install --save";
412
424
  const { stderr } = await execCommand(`${installDevDependencyCommand} ${SM_PACKAGE_NAME}`);
413
425
  const deps = depsForFramework(framework);
414
426
  if (deps)
415
427
  await execCommand(`${installDependencyCommand} ${deps}`);
428
+ return stderr;
429
+ }
430
+ async function installDeps(useYarn = false) {
431
+ const installCommand = useYarn ? "yarn" : "npm install";
432
+ const { stderr } = await execCommand(installCommand);
433
+ return stderr;
434
+ }
435
+ async function installRequiredDependencies(cwd, framework, skipDependencies) {
436
+ const yarnLock = NodeUtils__namespace.Files.exists(NodeUtils__namespace.YarnLockPath(cwd));
437
+ const spinner = spinner$1("Installing Slice Machine");
438
+ spinner.start();
439
+ const stderr = await (skipDependencies ? installDeps(yarnLock) : addAndInstallDeps(framework, yarnLock));
416
440
  const pathToPkg = path__default["default"].join(NodeUtils__namespace.PackagePaths(cwd).value(), SM_PACKAGE_NAME);
417
441
  const isPackageInstalled = NodeUtils__namespace.Files.exists(pathToPkg);
418
442
  if (isPackageInstalled || !stderr.length) {
@@ -672,17 +696,19 @@ async function loginOrBypass(base) {
672
696
 
673
697
  const defaultSliceMachineVersion = "0.0.41";
674
698
  async function configureProject(cwd, base, repositoryDomainName, framework, sliceLibPath = [], tracking = true) {
675
- const spinner = spinner$1(`Configuring your ${framework.value} & Prismic project...`);
699
+ const frameworkName = NodeUtils__namespace.Framework.fancyName(framework.value);
700
+ const spinner = spinner$1(`Configuring your ${frameworkName} and Prismic project...`);
676
701
  spinner.start();
677
702
  try {
678
703
  const manifest = NodeUtils__namespace.retrieveManifest(cwd);
679
704
  const packageJson = NodeUtils__namespace.retrieveJsonPackage(cwd);
680
705
  const sliceMachineVersionInstalled = getTheSliceMachineVersionInstalled(packageJson);
681
706
  const manifestAlreadyExistWithContent = manifest.exists && manifest.content;
707
+ const libs = manifest.content && manifest.content.libraries && manifest.content.libraries.length > 0 ? manifest.content.libraries : ["@/slices"];
682
708
  const manifestUpdated = {
683
709
  ...manifestAlreadyExistWithContent ? manifest.content : { _latest: sliceMachineVersionInstalled },
684
710
  apiEndpoint: Prismic__namespace.Endpoints.buildRepositoryEndpoint(base, repositoryDomainName),
685
- libraries: ["@/slices", ...sliceLibPath],
711
+ libraries: [...libs, ...sliceLibPath],
686
712
  ...framework.manuallyAdded ? { framework: framework.value } : {},
687
713
  ...!tracking ? { tracking } : {}
688
714
  };
@@ -691,7 +717,7 @@ async function configureProject(cwd, base, repositoryDomainName, framework, slic
691
717
  else
692
718
  NodeUtils__namespace.patchManifest(cwd, manifestUpdated);
693
719
  const pathToSlicesFolder = NodeUtils__namespace.CustomPaths(cwd).library("slices").value();
694
- if (!NodeUtils__namespace.Files.exists(pathToSlicesFolder)) {
720
+ if (!NodeUtils__namespace.Files.exists(pathToSlicesFolder) && libs.includes("@/slices")) {
695
721
  NodeUtils__namespace.Files.mkdir(pathToSlicesFolder, { recursive: true });
696
722
  }
697
723
  NodeUtils__namespace.addJsonPackageSmScript(cwd);
@@ -729,7 +755,8 @@ const extractVersionNumberFromSemver = (semver) => {
729
755
  function displayFinalMessage(cwd) {
730
756
  const yarnLock = NodeUtils__namespace.Files.exists(NodeUtils__namespace.YarnLockPath(cwd));
731
757
  const command = `${yarnLock ? "yarn" : "npm"} run ${core.CONSTS.SCRIPT_NAME}`;
732
- console.log(`${white("\u25A0")} Run ${purple(command)} to now launch Slice Machine`);
758
+ console.log();
759
+ console.log(`${white("\u25A0")} Run ${purple(command)} to start Slice Machine`);
733
760
  }
734
761
 
735
762
  const Dependencies = {
@@ -837,6 +864,290 @@ async function installLib(cwd, libGithubPath, branch = "HEAD") {
837
864
  }
838
865
  }
839
866
 
867
+ function handelErrors(prefix, err) {
868
+ if (axios__default["default"].isAxiosError(err) && err.response) {
869
+ writeError$1(`${prefix} | [${err.response.status}]: ${err.response.statusText}`);
870
+ } else if (err instanceof Error) {
871
+ writeError$1(`${prefix} ${err.message}`);
872
+ } else {
873
+ writeError$1(`${prefix} ${String(err)}`);
874
+ }
875
+ }
876
+ async function getRemoteSliceIds(customTypeApiEndpoint, repository, authorization) {
877
+ const addr = `${stripLastSlash(customTypeApiEndpoint)}/slices`;
878
+ return axios__default["default"].get(addr, {
879
+ headers: {
880
+ Authorization: `Bearer ${authorization}`,
881
+ repository
882
+ }
883
+ }).then((res) => {
884
+ return Array.isArray(res.data) ? res.data.map((model) => model.id) : [];
885
+ });
886
+ }
887
+ async function sendModelToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, model) {
888
+ const data = models.Slices.fromSM(model);
889
+ const updateOrInsertUrl = `${customTypesApiEndpoint}slices/${remoteSliceIds.includes(model.id) ? "update" : "insert"}`;
890
+ return axios__default["default"].post(updateOrInsertUrl, data, {
891
+ headers: {
892
+ Authorization: `Bearer ${authorization}`,
893
+ repository
894
+ }
895
+ }).then(() => {
896
+ return;
897
+ }).catch((err) => {
898
+ handelErrors(`sending slice ${model.id}, please try again. If the problem persists, contact us.`, err);
899
+ throw err;
900
+ });
901
+ }
902
+ async function sendManyModelsToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, models) {
903
+ return Promise.all(models.map((model) => sendModelToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, model))).then(() => {
904
+ return;
905
+ }).catch(() => {
906
+ process.exit(1);
907
+ });
908
+ }
909
+ function stripLastSlash(str) {
910
+ return str.replace(/\/*$/g, "");
911
+ }
912
+ function getRemoteCustomTypeIds(customTypeApiEndpoint, repository, authorization) {
913
+ const addr = `${stripLastSlash(customTypeApiEndpoint)}/customtypes`;
914
+ return axios__default["default"].get(addr, {
915
+ headers: {
916
+ Authorization: `Bearer ${authorization}`,
917
+ repository
918
+ }
919
+ }).then((res) => {
920
+ return Array.isArray(res.data) ? res.data.map((ct) => ct.id) : [];
921
+ });
922
+ }
923
+ async function sendCustomTypeToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customType) {
924
+ const shouldUpdate = remoteCustomTypeIds.includes(customType.id);
925
+ const addr = `${stripLastSlash(customTypeApiEndpoint)}/customtypes/${shouldUpdate ? "update" : "insert"}`;
926
+ return axios__default["default"].post(addr, customType, {
927
+ headers: {
928
+ repository,
929
+ Authorization: `Bearer ${authorization}`
930
+ }
931
+ }).then(() => {
932
+ return;
933
+ }).catch((err) => {
934
+ handelErrors(`sending custom type ${customType.id}, please try again. If the problem persists, contact us.`, err);
935
+ throw err;
936
+ });
937
+ }
938
+ async function sendManyCustomTypesToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customTypes) {
939
+ return Promise.all(customTypes.map((customType) => sendCustomTypeToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customType))).then(() => {
940
+ return;
941
+ }).catch(() => {
942
+ process.exit(1);
943
+ });
944
+ }
945
+
946
+ const ProductionApisEndpoints = {
947
+ Models: "https://customtypes.prismic.io/",
948
+ AclProvider: "https://0yyeb2g040.execute-api.us-east-1.amazonaws.com/prod/"
949
+ };
950
+ const StageApisEndpoints = {
951
+ Models: "https://customtypes.wroom.io/",
952
+ AclProvider: "https://2iamcvnxf4.execute-api.us-east-1.amazonaws.com/stage/"
953
+ };
954
+ const getEndpointsFromBase = (base) => {
955
+ const url = new URL(base);
956
+ if (url.hostname === "wroom.io")
957
+ return StageApisEndpoints;
958
+ return ProductionApisEndpoints;
959
+ };
960
+
961
+ async function promptToPushSlices() {
962
+ return inquirer__default["default"].prompt([
963
+ {
964
+ type: "confirm",
965
+ name: "pushSlices",
966
+ default: false,
967
+ message: "Your repository already contains Slices. Do you want to continue pushing your local Slices?"
968
+ }
969
+ ]).then((res) => res.pushSlices);
970
+ }
971
+ async function promptToPushCustomTypes() {
972
+ return inquirer__default["default"].prompt([
973
+ {
974
+ type: "confirm",
975
+ name: "pushCustomTypes",
976
+ default: false,
977
+ message: "Your repository already contains Custom Types. Do you want to continue pushing your local Slices?"
978
+ }
979
+ ]).then((res) => res.pushCustomTypes);
980
+ }
981
+
982
+ async function createAcl(address, repository, authorization) {
983
+ return axios__default["default"].get(address + "create", {
984
+ headers: {
985
+ repository,
986
+ Authorization: `Bearer ${authorization}`,
987
+ "User-Agent": "slice-machine"
988
+ }
989
+ }).then((res) => res.data);
990
+ }
991
+ async function createFormForS3(key, filename, filePath, acl) {
992
+ const form = new FormData__default["default"]();
993
+ Object.entries(acl.values.fields).forEach(([k, value]) => {
994
+ form.append(k, value);
995
+ });
996
+ form.append("key", key);
997
+ const contentType = mime__default["default"].getType(filePath);
998
+ contentType && form.append("Content-Type", contentType);
999
+ return fs__default["default"].promises.readFile(filePath).then((file) => {
1000
+ form.append("file", file, { filename });
1001
+ return form;
1002
+ }).catch(() => {
1003
+ writeError$1(`Error reading preview image: ${filename}`);
1004
+ return null;
1005
+ });
1006
+ }
1007
+ function createS3Key(repository, sliceName, variationId, filename) {
1008
+ return `${repository}/shared-slices/${snakeCase__default["default"](sliceName)}/${snakeCase__default["default"](variationId)}-${uniqid__default["default"]()}/${filename}`;
1009
+ }
1010
+ async function sendVariationPreviewToS3(acl, repository, sliceName, variationId, filePath) {
1011
+ const filename = path__default["default"].basename(filePath);
1012
+ const key = createS3Key(repository, sliceName, variationId, filename);
1013
+ const form = await createFormForS3(key, filename, filePath, acl);
1014
+ if (form === null)
1015
+ return null;
1016
+ if (form.hasKnownLength() === false) {
1017
+ writeError$1(`[slice/push] An error occurred while uploading preview image ${filePath} as length in unknown`);
1018
+ }
1019
+ const errorMessage = `[slice/push] An error occurred while uploading preview images for ${sliceName}-${variationId} - please contact support`;
1020
+ return axios__default["default"].post(acl.values.url, form, {
1021
+ headers: {
1022
+ ...form.getHeaders(),
1023
+ "Content-Length": String(form.getLengthSync())
1024
+ }
1025
+ }).then((res) => {
1026
+ if (res.status !== 204) {
1027
+ writeError$1(errorMessage);
1028
+ writeError$1(`${res.status}: ${res.statusText}`);
1029
+ return null;
1030
+ } else {
1031
+ return `${acl.imgixEndpoint}/${key}`;
1032
+ }
1033
+ }).catch((err) => {
1034
+ writeError$1(errorMessage);
1035
+ if (axios__default["default"].isAxiosError(err) && err.response) {
1036
+ writeError$1(`${err.response.status}: ${err.response.statusText}`);
1037
+ } else if (err instanceof Error) {
1038
+ writeError$1(err.message);
1039
+ } else {
1040
+ writeError$1(String(err));
1041
+ }
1042
+ return null;
1043
+ });
1044
+ }
1045
+ async function maybeAddImageUrlToVariation(acl, repository, modelId, pathToScreenShot, variation) {
1046
+ const imageUrl = await sendVariationPreviewToS3(acl, repository, modelId, variation.id, pathToScreenShot);
1047
+ if (!imageUrl)
1048
+ return variation;
1049
+ return {
1050
+ ...variation,
1051
+ imageUrl
1052
+ };
1053
+ }
1054
+ async function addImageUrlsToVariations(acl, repository, modelId, screenshotPaths, variations) {
1055
+ return Promise.all(variations.map(async (variation) => {
1056
+ const screenshot = screenshotPaths[variation.id];
1057
+ if (!screenshot || !screenshot.path)
1058
+ return variation;
1059
+ return maybeAddImageUrlToVariation(acl, repository, modelId, screenshot.path, variation);
1060
+ }));
1061
+ }
1062
+ async function maybeUpdateModelVariationsWithImageUrl(acl, repository, component) {
1063
+ const { screenshotPaths, model } = component;
1064
+ const variations = await addImageUrlsToVariations(acl, repository, model.id, screenshotPaths, model.variations);
1065
+ return {
1066
+ ...model,
1067
+ variations
1068
+ };
1069
+ }
1070
+ async function addImageUrlsToModelVariations(acl, repository, components) {
1071
+ return Promise.all(components.map(async (component) => maybeUpdateModelVariationsWithImageUrl(acl, repository, component)));
1072
+ }
1073
+
1074
+ async function sendSlicesFromStarter(base, repository, authorization, libraryPaths, cwd) {
1075
+ const endpoints = getEndpointsFromBase(base);
1076
+ const libraries = Libraries__namespace.libraries(cwd, libraryPaths);
1077
+ if (libraries.length === 0)
1078
+ return Promise.resolve(false);
1079
+ const remoteSlices = await getRemoteSliceIds(endpoints.Models, repository, authorization);
1080
+ if (remoteSlices.length) {
1081
+ const pushAnyway = await promptToPushSlices();
1082
+ if (pushAnyway === false)
1083
+ return Promise.resolve(true);
1084
+ }
1085
+ const spinner = spinner$1("Pushing existing Slice models to your repository");
1086
+ spinner.start();
1087
+ const acl = await createAcl(endpoints.AclProvider, repository, authorization);
1088
+ const components = libraries.reduce((acc, lib) => {
1089
+ return [...acc, ...lib.components];
1090
+ }, []);
1091
+ const models = await addImageUrlsToModelVariations(acl, repository, components);
1092
+ await sendManyModelsToPrismic(repository, authorization, endpoints.Models, remoteSlices, models);
1093
+ spinner.succeed();
1094
+ return Promise.resolve(true);
1095
+ }
1096
+
1097
+ function readCustomTypes(cwd) {
1098
+ const customTypePaths = NodeUtils.CustomTypesPaths(cwd);
1099
+ const dir = customTypePaths.value();
1100
+ if (NodeUtils.Files.isDirectory(dir) === false)
1101
+ return [];
1102
+ const fileNames = NodeUtils.Files.readDirectory(dir);
1103
+ const files = fileNames.reduce((acc, fileName) => {
1104
+ const filePath = customTypePaths.customType(fileName).model();
1105
+ const json = NodeUtils.Files.safeReadJson(filePath);
1106
+ if (!json)
1107
+ return acc;
1108
+ const file = customtypes.CustomType.decode(json);
1109
+ if (file instanceof Error) {
1110
+ writeError$1(`reading ${filePath}: ${file.message}`);
1111
+ return acc;
1112
+ }
1113
+ if (Either$1.isLeft(file)) {
1114
+ writeError$1(`validating ${filePath}: ${JSON.stringify(file.left)}`);
1115
+ return acc;
1116
+ }
1117
+ return [...acc, file.right];
1118
+ }, []);
1119
+ return files;
1120
+ }
1121
+ async function sendCustomTypesFromStarter(repository, authorization, base, cwd) {
1122
+ const customTypeApiEndpoint = getEndpointsFromBase(base).Models;
1123
+ const customTypes = readCustomTypes(cwd);
1124
+ if (customTypes.length === 0)
1125
+ return Promise.resolve(false);
1126
+ const remoteCustomTypeIds = await getRemoteCustomTypeIds(customTypeApiEndpoint, repository, authorization);
1127
+ if (remoteCustomTypeIds.length) {
1128
+ const shouldPush = await promptToPushCustomTypes();
1129
+ if (shouldPush === false)
1130
+ return Promise.resolve(false);
1131
+ }
1132
+ const spinner = spinner$1("Pushing existing custom types to your repository");
1133
+ spinner.start();
1134
+ await sendManyCustomTypesToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customTypes);
1135
+ spinner.succeed();
1136
+ return Promise.resolve(true);
1137
+ }
1138
+
1139
+ async function sendStarterData(repository, base, cookies, cwd) {
1140
+ const smJson = NodeUtils.retrieveManifest(cwd);
1141
+ const hasDocuments = NodeUtils.Files.exists(path__default["default"].join(cwd, "documents"));
1142
+ if (smJson.exists === false || hasDocuments === false)
1143
+ return Promise.resolve(false);
1144
+ const authTokenFromCookie = cookie.parsePrismicAuthToken(cookies);
1145
+ if (smJson.content && smJson.content.libraries) {
1146
+ await sendSlicesFromStarter(base, repository, authTokenFromCookie, smJson.content.libraries, cwd);
1147
+ }
1148
+ return sendCustomTypesFromStarter(repository, authTokenFromCookie, base, cwd);
1149
+ }
1150
+
840
1151
  async function init() {
841
1152
  const cwd = findArgument(process.argv, "cwd") || process.cwd();
842
1153
  const base = findArgument(process.argv, "base") || core.CONSTS.DEFAULT_BASE;
@@ -844,7 +1155,7 @@ async function init() {
844
1155
  const branch = findArgument(process.argv, "branch");
845
1156
  const isTrackingAvailable = findArgument(process.argv, "tracking") !== "false";
846
1157
  const maybeRepositorySubdomain = findArgument(process.argv, "repository");
847
- Tracker.get().initialize("ED3O1FVsa8DteNyRmAuDyMcPoftJ6VdP" , isTrackingAvailable);
1158
+ Tracker.get().initialize("JfTfmHaATChc4xueS7RcCBsixI71dJIJ" , isTrackingAvailable);
848
1159
  void Tracker.get().trackInitStart(maybeRepositorySubdomain);
849
1160
  console.log(purple("You're about to configure Slicemachine... Press ctrl + C to cancel"));
850
1161
  validatePkg(cwd);
@@ -859,9 +1170,10 @@ async function init() {
859
1170
  const frameworkResult = await detectFramework(cwd);
860
1171
  const repositoryDomainName = await chooseOrCreateARepository(cwd, frameworkResult.value, config.cookies, config.base, maybeRepositorySubdomain);
861
1172
  Tracker.get().setRepository(repositoryDomainName);
862
- await installRequiredDependencies(cwd, frameworkResult.value);
863
1173
  const sliceLibPath = lib ? await installLib(cwd, lib, branch) : void 0;
1174
+ const wasStarter = await sendStarterData(repositoryDomainName, config.base, config.cookies, cwd);
864
1175
  await configureProject(cwd, base, repositoryDomainName, frameworkResult, sliceLibPath, isTrackingAvailable);
1176
+ await installRequiredDependencies(cwd, frameworkResult.value, wasStarter);
865
1177
  displayFinalMessage(cwd);
866
1178
  }
867
1179
  init().then(() => {