@tinacms/cli 1.4.0 → 1.5.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/index.js CHANGED
@@ -31,7 +31,7 @@ module.exports = __toCommonJS(src_exports);
31
31
  var import_clipanion5 = require("clipanion");
32
32
 
33
33
  // package.json
34
- var version = "1.4.0";
34
+ var version = "1.5.0";
35
35
 
36
36
  // src/next/commands/dev-command/index.ts
37
37
  var import_clipanion = require("clipanion");
@@ -45,7 +45,6 @@ var import_fs_extra = __toESM(require("fs-extra"));
45
45
  var import_path = __toESM(require("path"));
46
46
  var import_os = __toESM(require("os"));
47
47
  var esbuild = __toESM(require("esbuild"));
48
- var url = __toESM(require("url"));
49
48
  var dotenv = __toESM(require("dotenv"));
50
49
  var import_normalize_path = __toESM(require("normalize-path"));
51
50
 
@@ -165,9 +164,14 @@ var GRAPHQL_GQL_FILE = "schema.gql";
165
164
  var SCHEMA_JSON_FILE = "_schema.json";
166
165
  var LOOKUP_JSON_FILE = "_lookup.json";
167
166
  var ConfigManager = class {
168
- constructor(rootPath = process.cwd(), tinaGraphQLVersion) {
167
+ constructor({
168
+ rootPath = process.cwd(),
169
+ tinaGraphQLVersion,
170
+ legacyNoSDK
171
+ }) {
169
172
  this.rootPath = (0, import_normalize_path.default)(rootPath);
170
173
  this.tinaGraphQLVersionFromCLI = tinaGraphQLVersion;
174
+ this.legacyNoSDK = legacyNoSDK;
171
175
  }
172
176
  isUsingTs() {
173
177
  return [".ts", ".tsx"].includes(import_path.default.extname(this.tinaConfigFilePath));
@@ -178,6 +182,13 @@ var ConfigManager = class {
178
182
  hasSeparateContentRoot() {
179
183
  return this.rootPath !== this.contentRootPath;
180
184
  }
185
+ shouldSkipSDK() {
186
+ var _a;
187
+ if (this.legacyNoSDK) {
188
+ return this.legacyNoSDK;
189
+ }
190
+ return ((_a = this.config.client) == null ? void 0 : _a.skip) || false;
191
+ }
181
192
  async processConfig() {
182
193
  this.tinaFolderPath = await this.getTinaFolderPath(this.rootPath);
183
194
  this.envFilePath = import_path.default.resolve(
@@ -272,11 +283,8 @@ var ConfigManager = class {
272
283
  );
273
284
  this.outputHTMLFilePath = import_path.default.join(this.outputFolderPath, "index.html");
274
285
  this.outputGitignorePath = import_path.default.join(this.outputFolderPath, ".gitignore");
275
- this.spaHTMLPath = url.pathToFileURL(
276
- require.resolve("@tinacms/app")
277
- ).pathname;
278
- this.spaRootPath = this.spaHTMLPath.replace("/index.html", "");
279
- this.spaMainPath = import_path.default.join(this.spaRootPath, "src", "main.tsx");
286
+ this.spaMainPath = require.resolve("@tinacms/app");
287
+ this.spaRootPath = import_path.default.join(this.spaMainPath, "..", "..");
280
288
  }
281
289
  async getTinaFolderPath(rootPath) {
282
290
  const tinaFolderPath = import_path.default.join(rootPath, TINA_FOLDER);
@@ -416,166 +424,12 @@ var devHTML = (port) => `<!DOCTYPE html>
416
424
  </html>`;
417
425
 
418
426
  // src/next/commands/dev-command/server/index.ts
419
- var import_body_parser = __toESM(require("body-parser"));
420
- var import_path5 = __toESM(require("path"));
421
- var import_cors = __toESM(require("cors"));
422
427
  var import_vite2 = require("vite");
423
- var import_graphql = require("@tinacms/graphql");
424
-
425
- // src/next/commands/dev-command/server/media.ts
426
- var import_fs_extra2 = __toESM(require("fs-extra"));
427
- var import_path2 = __toESM(require("path"));
428
- var import_busboy = __toESM(require("busboy"));
429
- var createMediaRouter = (config3) => {
430
- const mediaFolder = import_path2.default.join(
431
- config3.rootPath,
432
- config3.publicFolder,
433
- config3.mediaRoot
434
- );
435
- const mediaModel = new MediaModel(config3);
436
- const handleList = async (req, res) => {
437
- const requestURL = new URL(req.url, config3.apiURL);
438
- const folder = requestURL.pathname.replace("/media/list/", "");
439
- const limit = requestURL.searchParams.get("limit");
440
- const cursor = requestURL.searchParams.get("cursor");
441
- const media = await mediaModel.listMedia({
442
- searchPath: folder,
443
- cursor,
444
- limit
445
- });
446
- res.end(JSON.stringify(media));
447
- };
448
- const handleDelete = async (req, res) => {
449
- const file = decodeURIComponent(req.url.slice("/media/".length));
450
- const didDelete = await mediaModel.deleteMedia({ searchPath: file });
451
- res.end(JSON.stringify(didDelete));
452
- };
453
- const handlePost = async function(req, res) {
454
- const bb = (0, import_busboy.default)({ headers: req.headers });
455
- bb.on("file", (name2, file, info) => {
456
- const saveTo = import_path2.default.join(mediaFolder, info.filename);
457
- file.pipe(import_fs_extra2.default.createWriteStream(saveTo));
458
- });
459
- bb.on("error", (error) => {
460
- res.statusCode = 500;
461
- if (error instanceof Error) {
462
- res.end(JSON.stringify({ message: error }));
463
- } else {
464
- res.end(JSON.stringify({ message: "Unknown error while uploading" }));
465
- }
466
- });
467
- bb.on("close", () => {
468
- res.statusCode = 200;
469
- res.end(JSON.stringify({ success: true }));
470
- });
471
- req.pipe(bb);
472
- };
473
- return { handleList, handleDelete, handlePost };
474
- };
475
- var parseMediaFolder = (str) => {
476
- let returnString = str;
477
- if (returnString.startsWith("/"))
478
- returnString = returnString.substr(1);
479
- if (returnString.endsWith("/"))
480
- returnString = returnString.substr(0, returnString.length - 1);
481
- return returnString;
482
- };
483
- var MediaModel = class {
484
- constructor({ rootPath, publicFolder, mediaRoot }) {
485
- this.rootPath = rootPath;
486
- this.mediaRoot = mediaRoot;
487
- this.publicFolder = publicFolder;
488
- }
489
- async listMedia(args) {
490
- try {
491
- const folderPath = (0, import_path2.join)(
492
- this.rootPath,
493
- this.publicFolder,
494
- this.mediaRoot,
495
- args.searchPath
496
- );
497
- const searchPath = parseMediaFolder(args.searchPath);
498
- const filesStr = await import_fs_extra2.default.readdir(folderPath);
499
- const filesProm = filesStr.map(async (file) => {
500
- const filePath = (0, import_path2.join)(folderPath, file);
501
- const stat = await import_fs_extra2.default.stat(filePath);
502
- let src = `/${file}`;
503
- const isFile = stat.isFile();
504
- if (!isFile) {
505
- return {
506
- isFile,
507
- size: stat.size,
508
- src,
509
- filename: file
510
- };
511
- }
512
- if (searchPath) {
513
- src = `/${searchPath}${src}`;
514
- }
515
- if (this.mediaRoot) {
516
- src = `/${this.mediaRoot}${src}`;
517
- }
518
- return {
519
- isFile,
520
- size: stat.size,
521
- src,
522
- filename: file
523
- };
524
- });
525
- const offset = Number(args.cursor) || 0;
526
- const limit = Number(args.limit) || 20;
527
- const rawItems = await Promise.all(filesProm);
528
- const sortedItems = rawItems.sort((a, b) => {
529
- if (a.isFile && !b.isFile) {
530
- return 1;
531
- }
532
- if (!a.isFile && b.isFile) {
533
- return -1;
534
- }
535
- return 0;
536
- });
537
- const limitItems = sortedItems.slice(offset, offset + limit);
538
- const files = limitItems.filter((x) => x.isFile);
539
- const directories = limitItems.filter((x) => !x.isFile).map((x) => x.src);
540
- const cursor = rawItems.length > offset + limit ? String(offset + limit) : null;
541
- return {
542
- files,
543
- directories,
544
- cursor
545
- };
546
- } catch (error) {
547
- console.error(error);
548
- return {
549
- files: [],
550
- directories: [],
551
- error: error == null ? void 0 : error.toString()
552
- };
553
- }
554
- }
555
- async deleteMedia(args) {
556
- try {
557
- const file = (0, import_path2.join)(
558
- this.rootPath,
559
- this.publicFolder,
560
- this.mediaRoot,
561
- args.searchPath
562
- );
563
- await import_fs_extra2.default.stat(file);
564
- await import_fs_extra2.default.remove(file);
565
- return { ok: true };
566
- } catch (error) {
567
- console.error(error);
568
- return { ok: false, message: error == null ? void 0 : error.toString() };
569
- }
570
- }
571
- };
572
-
573
- // src/next/commands/dev-command/server/index.ts
574
- var import_esbuild = require("esbuild");
575
428
 
576
429
  // src/next/vite/index.ts
577
- var import_path4 = __toESM(require("path"));
430
+ var import_path3 = __toESM(require("path"));
578
431
  var import_vite = require("vite");
432
+ var import_plugin_react = __toESM(require("@vitejs/plugin-react"));
579
433
 
580
434
  // src/next/vite/tailwind.ts
581
435
  var import_tailwindcss = __toESM(require("tailwindcss"));
@@ -585,15 +439,15 @@ var import_defaultTheme = __toESM(require("tailwindcss/defaultTheme.js"));
585
439
  var import_typography = __toESM(require("@tailwindcss/typography"));
586
440
  var import_line_clamp = __toESM(require("@tailwindcss/line-clamp"));
587
441
  var import_aspect_ratio = __toESM(require("@tailwindcss/aspect-ratio"));
588
- var import_path3 = __toESM(require("path"));
442
+ var import_path2 = __toESM(require("path"));
589
443
  var tinaTailwind = (spaPath, configFilePath) => {
590
444
  return {
591
445
  name: "vite-plugin-tina",
592
446
  config: (viteConfig) => {
593
447
  const plugins = [];
594
448
  const content2 = [
595
- import_path3.default.join(spaPath, "src/**/*.{vue,js,ts,jsx,tsx,svelte}"),
596
- import_path3.default.join(configFilePath)
449
+ import_path2.default.join(spaPath, "src/**/*.{vue,js,ts,jsx,tsx,svelte}"),
450
+ import_path2.default.join(configFilePath, "../**/*.{vue,js,ts,jsx,tsx,svelte}")
597
451
  ];
598
452
  const tw = (0, import_tailwindcss.default)({
599
453
  important: ".tina-tailwind",
@@ -837,7 +691,6 @@ var createConfig = async ({
837
691
  database,
838
692
  apiURL,
839
693
  plugins = [],
840
- noSDK,
841
694
  noWatch,
842
695
  rollupOptions
843
696
  }) => {
@@ -862,8 +715,8 @@ var createConfig = async ({
862
715
  TINA_IMPORT: configManager.tinaConfigFilePath,
863
716
  SCHEMA_IMPORT: configManager.generatedGraphQLJSONPath
864
717
  };
865
- if (noSDK) {
866
- alias["CLIENT_IMPORT"] = import_path4.default.join(
718
+ if (configManager.shouldSkipSDK()) {
719
+ alias["CLIENT_IMPORT"] = import_path3.default.join(
867
720
  configManager.spaRootPath,
868
721
  "src",
869
722
  "dummy-client.ts"
@@ -899,12 +752,13 @@ var createConfig = async ({
899
752
  }
900
753
  },
901
754
  build: {
902
- sourcemap: true,
755
+ sourcemap: false,
903
756
  outDir: configManager.outputFolderPath,
904
757
  emptyOutDir: true,
905
758
  rollupOptions
906
759
  },
907
760
  plugins: [
761
+ (0, import_plugin_react.default)(),
908
762
  (0, import_vite.splitVendorChunkPlugin)(),
909
763
  tinaTailwind(configManager.spaRootPath, configManager.tinaConfigFilePath),
910
764
  ...plugins
@@ -913,77 +767,246 @@ var createConfig = async ({
913
767
  return config3;
914
768
  };
915
769
 
916
- // src/next/commands/dev-command/server/index.ts
917
- var createDevServer = async (configManager, database, apiURL, noSDK, noWatch) => {
918
- const plugins = [
919
- {
920
- name: "transform-tsx",
921
- async transform(code, id) {
922
- if (id.startsWith(configManager.rootPath)) {
923
- const extName = import_path5.default.extname(id);
924
- if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
925
- const result = await (0, import_esbuild.transform)(code, { loader: "tsx" });
926
- return {
927
- code: result.code
928
- };
929
- }
770
+ // src/next/vite/plugins.ts
771
+ var import_esbuild = require("esbuild");
772
+ var import_path5 = __toESM(require("path"));
773
+ var import_body_parser = __toESM(require("body-parser"));
774
+ var import_cors = __toESM(require("cors"));
775
+ var import_graphql = require("@tinacms/graphql");
776
+
777
+ // src/next/commands/dev-command/server/media.ts
778
+ var import_fs_extra2 = __toESM(require("fs-extra"));
779
+ var import_path4 = __toESM(require("path"));
780
+ var import_busboy = __toESM(require("busboy"));
781
+ var createMediaRouter = (config3) => {
782
+ const mediaFolder = import_path4.default.join(
783
+ config3.rootPath,
784
+ config3.publicFolder,
785
+ config3.mediaRoot
786
+ );
787
+ const mediaModel = new MediaModel(config3);
788
+ const handleList = async (req, res) => {
789
+ const requestURL = new URL(req.url, config3.apiURL);
790
+ const folder = requestURL.pathname.replace("/media/list/", "");
791
+ const limit = requestURL.searchParams.get("limit");
792
+ const cursor = requestURL.searchParams.get("cursor");
793
+ const media = await mediaModel.listMedia({
794
+ searchPath: folder,
795
+ cursor,
796
+ limit
797
+ });
798
+ res.end(JSON.stringify(media));
799
+ };
800
+ const handleDelete = async (req, res) => {
801
+ const file = decodeURIComponent(req.url.slice("/media/".length));
802
+ const didDelete = await mediaModel.deleteMedia({ searchPath: file });
803
+ res.end(JSON.stringify(didDelete));
804
+ };
805
+ const handlePost = async function(req, res) {
806
+ const bb = (0, import_busboy.default)({ headers: req.headers });
807
+ bb.on("file", (name2, file, info) => {
808
+ const saveTo = import_path4.default.join(mediaFolder, info.filename);
809
+ file.pipe(import_fs_extra2.default.createWriteStream(saveTo));
810
+ });
811
+ bb.on("error", (error) => {
812
+ res.statusCode = 500;
813
+ if (error instanceof Error) {
814
+ res.end(JSON.stringify({ message: error }));
815
+ } else {
816
+ res.end(JSON.stringify({ message: "Unknown error while uploading" }));
817
+ }
818
+ });
819
+ bb.on("close", () => {
820
+ res.statusCode = 200;
821
+ res.end(JSON.stringify({ success: true }));
822
+ });
823
+ req.pipe(bb);
824
+ };
825
+ return { handleList, handleDelete, handlePost };
826
+ };
827
+ var parseMediaFolder = (str) => {
828
+ let returnString = str;
829
+ if (returnString.startsWith("/"))
830
+ returnString = returnString.substr(1);
831
+ if (returnString.endsWith("/"))
832
+ returnString = returnString.substr(0, returnString.length - 1);
833
+ return returnString;
834
+ };
835
+ var MediaModel = class {
836
+ constructor({ rootPath, publicFolder, mediaRoot }) {
837
+ this.rootPath = rootPath;
838
+ this.mediaRoot = mediaRoot;
839
+ this.publicFolder = publicFolder;
840
+ }
841
+ async listMedia(args) {
842
+ try {
843
+ const folderPath = (0, import_path4.join)(
844
+ this.rootPath,
845
+ this.publicFolder,
846
+ this.mediaRoot,
847
+ args.searchPath
848
+ );
849
+ const searchPath = parseMediaFolder(args.searchPath);
850
+ const filesStr = await import_fs_extra2.default.readdir(folderPath);
851
+ const filesProm = filesStr.map(async (file) => {
852
+ const filePath = (0, import_path4.join)(folderPath, file);
853
+ const stat = await import_fs_extra2.default.stat(filePath);
854
+ let src = `/${file}`;
855
+ const isFile = stat.isFile();
856
+ if (!isFile) {
857
+ return {
858
+ isFile,
859
+ size: stat.size,
860
+ src,
861
+ filename: file
862
+ };
863
+ }
864
+ if (searchPath) {
865
+ src = `/${searchPath}${src}`;
930
866
  }
867
+ if (this.mediaRoot) {
868
+ src = `/${this.mediaRoot}${src}`;
869
+ }
870
+ return {
871
+ isFile,
872
+ size: stat.size,
873
+ src,
874
+ filename: file
875
+ };
876
+ });
877
+ const offset = Number(args.cursor) || 0;
878
+ const limit = Number(args.limit) || 20;
879
+ const rawItems = await Promise.all(filesProm);
880
+ const sortedItems = rawItems.sort((a, b) => {
881
+ if (a.isFile && !b.isFile) {
882
+ return 1;
883
+ }
884
+ if (!a.isFile && b.isFile) {
885
+ return -1;
886
+ }
887
+ return 0;
888
+ });
889
+ const limitItems = sortedItems.slice(offset, offset + limit);
890
+ const files = limitItems.filter((x) => x.isFile);
891
+ const directories = limitItems.filter((x) => !x.isFile).map((x) => x.src);
892
+ const cursor = rawItems.length > offset + limit ? String(offset + limit) : null;
893
+ return {
894
+ files,
895
+ directories,
896
+ cursor
897
+ };
898
+ } catch (error) {
899
+ console.error(error);
900
+ return {
901
+ files: [],
902
+ directories: [],
903
+ error: error == null ? void 0 : error.toString()
904
+ };
905
+ }
906
+ }
907
+ async deleteMedia(args) {
908
+ try {
909
+ const file = (0, import_path4.join)(
910
+ this.rootPath,
911
+ this.publicFolder,
912
+ this.mediaRoot,
913
+ args.searchPath
914
+ );
915
+ await import_fs_extra2.default.stat(file);
916
+ await import_fs_extra2.default.remove(file);
917
+ return { ok: true };
918
+ } catch (error) {
919
+ console.error(error);
920
+ return { ok: false, message: error == null ? void 0 : error.toString() };
921
+ }
922
+ }
923
+ };
924
+
925
+ // src/next/vite/plugins.ts
926
+ var transformTsxPlugin = ({
927
+ configManager: _configManager
928
+ }) => {
929
+ const plug = {
930
+ name: "transform-tsx",
931
+ async transform(code, id) {
932
+ const extName = import_path5.default.extname(id);
933
+ if (extName.startsWith(".tsx") || extName.startsWith(".ts")) {
934
+ const result = await (0, import_esbuild.transform)(code, { loader: "tsx" });
935
+ return {
936
+ code: result.code
937
+ };
931
938
  }
932
- },
933
- {
934
- name: "graphql-endpoints",
935
- configureServer(server) {
936
- server.middlewares.use((0, import_cors.default)());
937
- server.middlewares.use(import_body_parser.default.json());
938
- server.middlewares.use(async (req, res, next) => {
939
- var _a;
940
- const mediaPaths = (_a = configManager.config.media) == null ? void 0 : _a.tina;
941
- const mediaRouter = createMediaRouter({
942
- rootPath: configManager.rootPath,
943
- apiURL,
944
- publicFolder: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.publicFolder) || ""),
945
- mediaRoot: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.mediaRoot) || "")
946
- });
947
- if (req.url.startsWith("/media/upload")) {
948
- await mediaRouter.handlePost(req, res);
949
- return;
950
- }
951
- if (req.url.startsWith("/media")) {
952
- if (req.method === "DELETE") {
953
- await mediaRouter.handleDelete(req, res);
954
- return;
955
- }
956
- }
957
- if (req.url.startsWith("/media/list")) {
958
- await mediaRouter.handleList(req, res);
959
- return;
960
- }
961
- if (req.url === "/altair") {
962
- res.end(
963
- JSON.stringify({
964
- status: "The GraphQL playground has moved to <your-dev-url>/index.html#/graphql"
965
- })
966
- );
967
- return;
968
- }
969
- if (req.url === "/graphql") {
970
- const { query, variables } = req.body;
971
- const result = await (0, import_graphql.resolve)({
972
- config: {
973
- useRelativeMedia: true
974
- },
975
- database,
976
- query,
977
- variables,
978
- verbose: false
979
- });
980
- res.end(JSON.stringify(result));
939
+ }
940
+ };
941
+ return plug;
942
+ };
943
+ var devServerEndPointsPlugin = ({
944
+ configManager,
945
+ apiURL,
946
+ database
947
+ }) => {
948
+ const plug = {
949
+ name: "graphql-endpoints",
950
+ configureServer(server) {
951
+ server.middlewares.use((0, import_cors.default)());
952
+ server.middlewares.use(import_body_parser.default.json());
953
+ server.middlewares.use(async (req, res, next) => {
954
+ var _a;
955
+ const mediaPaths = (_a = configManager.config.media) == null ? void 0 : _a.tina;
956
+ const mediaRouter = createMediaRouter({
957
+ rootPath: configManager.rootPath,
958
+ apiURL,
959
+ publicFolder: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.publicFolder) || ""),
960
+ mediaRoot: parseMediaFolder((mediaPaths == null ? void 0 : mediaPaths.mediaRoot) || "")
961
+ });
962
+ if (req.url.startsWith("/media/upload")) {
963
+ await mediaRouter.handlePost(req, res);
964
+ return;
965
+ }
966
+ if (req.url.startsWith("/media")) {
967
+ if (req.method === "DELETE") {
968
+ await mediaRouter.handleDelete(req, res);
981
969
  return;
982
970
  }
983
- next();
984
- });
985
- }
971
+ }
972
+ if (req.url.startsWith("/media/list")) {
973
+ await mediaRouter.handleList(req, res);
974
+ return;
975
+ }
976
+ if (req.url === "/altair") {
977
+ res.end(
978
+ JSON.stringify({
979
+ status: "The GraphQL playground has moved to <your-dev-url>/index.html#/graphql"
980
+ })
981
+ );
982
+ return;
983
+ }
984
+ if (req.url === "/graphql") {
985
+ const { query, variables } = req.body;
986
+ const result = await (0, import_graphql.resolve)({
987
+ config: {
988
+ useRelativeMedia: true
989
+ },
990
+ database,
991
+ query,
992
+ variables,
993
+ verbose: false
994
+ });
995
+ res.end(JSON.stringify(result));
996
+ return;
997
+ }
998
+ next();
999
+ });
986
1000
  }
1001
+ };
1002
+ return plug;
1003
+ };
1004
+
1005
+ // src/next/commands/dev-command/server/index.ts
1006
+ var createDevServer = async (configManager, database, apiURL, noWatch) => {
1007
+ const plugins = [
1008
+ transformTsxPlugin({ configManager }),
1009
+ devServerEndPointsPlugin({ apiURL, configManager, database })
987
1010
  ];
988
1011
  return (0, import_vite2.createServer)(
989
1012
  await createConfig({
@@ -991,7 +1014,6 @@ var createDevServer = async (configManager, database, apiURL, noSDK, noWatch) =>
991
1014
  database,
992
1015
  apiURL,
993
1016
  plugins,
994
- noSDK,
995
1017
  noWatch,
996
1018
  rollupOptions: {
997
1019
  input: configManager.spaMainPath
@@ -1204,14 +1226,12 @@ var Codegen = class {
1204
1226
  configManager,
1205
1227
  port,
1206
1228
  schema,
1207
- noSDK,
1208
1229
  queryDoc,
1209
1230
  fragDoc
1210
1231
  }) {
1211
1232
  this.configManager = configManager;
1212
1233
  this.port = port;
1213
1234
  this.schema = schema;
1214
- this.noSDK = noSDK;
1215
1235
  this.queryDoc = queryDoc;
1216
1236
  this.fragDoc = fragDoc;
1217
1237
  }
@@ -1226,7 +1246,7 @@ var Codegen = class {
1226
1246
  }
1227
1247
  async execute() {
1228
1248
  const apiURL = this.getApiURL();
1229
- if (this.noSDK) {
1249
+ if (this.configManager.shouldSkipSDK()) {
1230
1250
  await this.removeGeneratedFilesIfExists();
1231
1251
  return apiURL;
1232
1252
  }
@@ -1423,7 +1443,7 @@ var import_readable_stream = require("readable-stream");
1423
1443
  var import_net = require("net");
1424
1444
  var import_many_level = require("many-level");
1425
1445
  var import_memory_level = require("memory-level");
1426
- var createDBServer = () => {
1446
+ var createDBServer = (port) => {
1427
1447
  const levelHost = new import_many_level.ManyLevelHost(
1428
1448
  new import_memory_level.MemoryLevel({
1429
1449
  valueEncoding: "json"
@@ -1435,10 +1455,12 @@ var createDBServer = () => {
1435
1455
  });
1436
1456
  dbServer.once("error", (err) => {
1437
1457
  if ((err == null ? void 0 : err.code) === "EADDRINUSE") {
1438
- throw new Error(`Tina Dev server is already in use`);
1458
+ throw new Error(
1459
+ `Tina Dev server is already in use. Datalayer server is busy on port ${port}`
1460
+ );
1439
1461
  }
1440
1462
  });
1441
- dbServer.listen(9e3);
1463
+ dbServer.listen(port);
1442
1464
  };
1443
1465
  async function createAndInitializeDatabase(configManager, bridgeOverride) {
1444
1466
  let database;
@@ -1508,6 +1530,9 @@ var DevCommand = class extends import_clipanion.Command {
1508
1530
  this.port = import_clipanion.Option.String("-p,--port", "4001", {
1509
1531
  description: "Specify a port to run the server on. (default 4001)"
1510
1532
  });
1533
+ this.datalayerPort = import_clipanion.Option.String("--datalayer-port", "9000", {
1534
+ description: "Specify a port to run the datalayer server on. (default 4001)"
1535
+ });
1511
1536
  this.subCommand = import_clipanion.Option.String("-c,--command", {
1512
1537
  description: "The sub-command to run"
1513
1538
  });
@@ -1530,7 +1555,7 @@ var DevCommand = class extends import_clipanion.Command {
1530
1555
  description: "Don't regenerate config on file changes"
1531
1556
  });
1532
1557
  this.noSDK = import_clipanion.Option.Boolean("--noSDK", false, {
1533
- description: "Don't generate the generated client SDK"
1558
+ description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
1534
1559
  });
1535
1560
  this.noTelemetry = import_clipanion.Option.Boolean("--noTelemetry", false, {
1536
1561
  description: "Disable anonymous telemetry that is collected"
@@ -1555,9 +1580,17 @@ var DevCommand = class extends import_clipanion.Command {
1555
1580
  "--experimentalDataLayer has been deprecated, the data layer is now built-in automatically"
1556
1581
  );
1557
1582
  }
1558
- const configManager = new ConfigManager(this.rootPath);
1583
+ if (this.noSDK) {
1584
+ logger.warn(
1585
+ "--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
1586
+ );
1587
+ }
1588
+ const configManager = new ConfigManager({
1589
+ rootPath: this.rootPath,
1590
+ legacyNoSDK: this.noSDK
1591
+ });
1559
1592
  logger.info("Starting Tina Dev Server");
1560
- createDBServer();
1593
+ createDBServer(Number(this.datalayerPort));
1561
1594
  let database = null;
1562
1595
  const setup = async ({ firstTime }) => {
1563
1596
  try {
@@ -1600,7 +1633,6 @@ var DevCommand = class extends import_clipanion.Command {
1600
1633
  schema: await (0, import_graphql8.getASTSchema)(database),
1601
1634
  configManager,
1602
1635
  port: Number(this.port),
1603
- noSDK: this.noSDK,
1604
1636
  queryDoc,
1605
1637
  fragDoc
1606
1638
  });
@@ -1637,7 +1669,6 @@ var DevCommand = class extends import_clipanion.Command {
1637
1669
  configManager,
1638
1670
  database,
1639
1671
  apiURL,
1640
- this.noSDK,
1641
1672
  this.noWatch
1642
1673
  );
1643
1674
  await server.listen(Number(this.port));
@@ -1689,7 +1720,7 @@ var DevCommand = class extends import_clipanion.Command {
1689
1720
  ]
1690
1721
  }
1691
1722
  ];
1692
- if (!this.noSDK) {
1723
+ if (!configManager.shouldSkipSDK()) {
1693
1724
  summaryItems.push({
1694
1725
  emoji: "\u{1F916}",
1695
1726
  heading: "Auto-generated files",
@@ -1786,7 +1817,7 @@ var import_graphql9 = require("@tinacms/graphql");
1786
1817
 
1787
1818
  // src/next/commands/build-command/server.ts
1788
1819
  var import_vite4 = require("vite");
1789
- var buildProductionSpa = async (configManager, database, apiURL, noSDK) => {
1820
+ var buildProductionSpa = async (configManager, database, apiURL) => {
1790
1821
  const publicEnv = {};
1791
1822
  Object.keys(process.env).forEach((key) => {
1792
1823
  if (key.startsWith("TINA_PUBLIC_") || key.startsWith("NEXT_PUBLIC_") || key === "NODE_ENV" || key === "HEAD") {
@@ -1805,10 +1836,10 @@ var buildProductionSpa = async (configManager, database, apiURL, noSDK) => {
1805
1836
  }
1806
1837
  });
1807
1838
  const config3 = await createConfig({
1839
+ plugins: [transformTsxPlugin({ configManager })],
1808
1840
  configManager,
1809
1841
  database,
1810
1842
  apiURL,
1811
- noSDK,
1812
1843
  noWatch: true
1813
1844
  });
1814
1845
  return (0, import_vite4.build)(config3);
@@ -1929,7 +1960,10 @@ var BuildCommand = class extends import_clipanion2.Command {
1929
1960
  description: "increase verbosity of logged output"
1930
1961
  });
1931
1962
  this.noSDK = import_clipanion2.Option.Boolean("--noSDK", false, {
1932
- description: "Don't generate the generated client SDK"
1963
+ description: "DEPRECATED - This should now be set in the config at client.skip = true'. Don't generate the generated client SDK"
1964
+ });
1965
+ this.datalayerPort = import_clipanion2.Option.String("--datalayer-port", "9000", {
1966
+ description: "Specify a port to run the datalayer server on. (default 4001)"
1933
1967
  });
1934
1968
  this.isomorphicGitBridge = import_clipanion2.Option.Boolean("--isomorphicGitBridge", {
1935
1969
  description: "DEPRECATED - Enable Isomorphic Git Bridge Implementation"
@@ -1952,10 +1986,11 @@ var BuildCommand = class extends import_clipanion2.Command {
1952
1986
  process.exit(1);
1953
1987
  }
1954
1988
  async execute() {
1955
- const configManager = new ConfigManager(
1956
- this.rootPath,
1957
- this.tinaGraphQLVersion
1958
- );
1989
+ const configManager = new ConfigManager({
1990
+ rootPath: this.rootPath,
1991
+ tinaGraphQLVersion: this.tinaGraphQLVersion,
1992
+ legacyNoSDK: this.noSDK
1993
+ });
1959
1994
  logger.info("Starting Tina build");
1960
1995
  if (this.isomorphicGitBridge) {
1961
1996
  logger.warn("--isomorphicGitBridge has been deprecated");
@@ -1968,6 +2003,11 @@ var BuildCommand = class extends import_clipanion2.Command {
1968
2003
  if (this.localOption) {
1969
2004
  logger.warn("--local has been deprecated");
1970
2005
  }
2006
+ if (this.noSDK) {
2007
+ logger.warn(
2008
+ "--noSDK has been deprecated, and will be unsupported in a future release. This should be set in the config at client.skip = true"
2009
+ );
2010
+ }
1971
2011
  try {
1972
2012
  await configManager.processConfig();
1973
2013
  } catch (e) {
@@ -1975,7 +2015,7 @@ var BuildCommand = class extends import_clipanion2.Command {
1975
2015
  logger.error("Unable to build, please fix your Tina config and try again");
1976
2016
  process.exit(1);
1977
2017
  }
1978
- createDBServer();
2018
+ createDBServer(Number(this.datalayerPort));
1979
2019
  const database = await createAndInitializeDatabase(configManager);
1980
2020
  const { queryDoc, fragDoc } = await (0, import_graphql9.buildSchema)(
1981
2021
  database,
@@ -1984,7 +2024,6 @@ var BuildCommand = class extends import_clipanion2.Command {
1984
2024
  const codegen2 = new Codegen({
1985
2025
  schema: await (0, import_graphql9.getASTSchema)(database),
1986
2026
  configManager,
1987
- noSDK: this.noSDK,
1988
2027
  queryDoc,
1989
2028
  fragDoc
1990
2029
  });
@@ -1992,13 +2031,13 @@ var BuildCommand = class extends import_clipanion2.Command {
1992
2031
  await this.checkClientInfo(configManager, apiURL);
1993
2032
  await waitForDB(configManager.config, apiURL, false);
1994
2033
  await this.checkGraphqlSchema(configManager, database, apiURL);
1995
- await buildProductionSpa(configManager, database, apiURL, this.noSDK);
2034
+ await buildProductionSpa(configManager, database, apiURL);
1996
2035
  await import_fs_extra5.default.outputFile(
1997
2036
  configManager.outputGitignorePath,
1998
2037
  "index.html\nassets/"
1999
2038
  );
2000
2039
  const summaryItems = [];
2001
- if (!this.noSDK) {
2040
+ if (!configManager.shouldSkipSDK()) {
2002
2041
  summaryItems.push({
2003
2042
  emoji: "\u{1F916}",
2004
2043
  heading: "Auto-generated files",
@@ -2036,13 +2075,13 @@ var BuildCommand = class extends import_clipanion2.Command {
2036
2075
  const { config: config3 } = configManager;
2037
2076
  const token = config3.token;
2038
2077
  const { clientId, branch, host } = (0, import_schema_tools2.parseURL)(apiURL);
2039
- const url2 = `https://${host}/db/${clientId}/status/${branch}`;
2078
+ const url = `https://${host}/db/${clientId}/status/${branch}`;
2040
2079
  const bar2 = new import_progress2.default("Checking clientId and token. :prog", 1);
2041
2080
  let branchKnown = false;
2042
2081
  try {
2043
2082
  const res = await request({
2044
2083
  token,
2045
- url: url2
2084
+ url
2046
2085
  });
2047
2086
  bar2.tick({
2048
2087
  prog: "\u2705"
@@ -2084,7 +2123,7 @@ var BuildCommand = class extends import_clipanion2.Command {
2084
2123
  fn: async () => {
2085
2124
  const res = await request({
2086
2125
  token,
2087
- url: url2
2126
+ url
2088
2127
  });
2089
2128
  if (this.verbose) {
2090
2129
  logger.info(
@@ -2157,8 +2196,8 @@ async function request(args) {
2157
2196
  headers.append("X-API-KEY", args.token);
2158
2197
  }
2159
2198
  headers.append("Content-Type", "application/json");
2160
- const url2 = args == null ? void 0 : args.url;
2161
- const res = await (0, import_node_fetch2.default)(url2, {
2199
+ const url = args == null ? void 0 : args.url;
2200
+ const res = await (0, import_node_fetch2.default)(url, {
2162
2201
  method: "GET",
2163
2202
  headers,
2164
2203
  redirect: "follow"
@@ -2192,7 +2231,7 @@ Message from server: ${json.message}`;
2192
2231
  };
2193
2232
  }
2194
2233
  var fetchRemoteGraphqlSchema = async ({
2195
- url: url2,
2234
+ url,
2196
2235
  token
2197
2236
  }) => {
2198
2237
  const headers = new import_node_fetch2.Headers();
@@ -2201,7 +2240,7 @@ var fetchRemoteGraphqlSchema = async ({
2201
2240
  }
2202
2241
  const body = JSON.stringify({ query: (0, import_graphql10.getIntrospectionQuery)(), variables: {} });
2203
2242
  headers.append("Content-Type", "application/json");
2204
- const res = await (0, import_node_fetch2.default)(url2, {
2243
+ const res = await (0, import_node_fetch2.default)(url, {
2205
2244
  method: "POST",
2206
2245
  headers,
2207
2246
  body
@@ -2212,13 +2251,12 @@ var fetchRemoteGraphqlSchema = async ({
2212
2251
 
2213
2252
  // src/next/commands/audit-command/index.ts
2214
2253
  var import_clipanion3 = require("clipanion");
2215
- var import_graphql13 = require("@tinacms/graphql");
2254
+ var import_graphql12 = require("@tinacms/graphql");
2216
2255
 
2217
2256
  // src/next/commands/audit-command/audit.ts
2218
2257
  var import_prompts = __toESM(require("prompts"));
2219
2258
  var import_metrics = require("@tinacms/metrics");
2220
2259
  var import_graphql11 = require("@tinacms/graphql");
2221
- var import_graphql12 = require("@tinacms/graphql");
2222
2260
  var import_chalk4 = __toESM(require("chalk"));
2223
2261
  var audit = async ({
2224
2262
  database,
@@ -2331,14 +2369,12 @@ var auditDocuments = async (args) => {
2331
2369
  }
2332
2370
  });
2333
2371
  }
2334
- const params = transformDocumentIntoMutationRequestPayload(
2372
+ const tinaSchema = await database.getSchema();
2373
+ const values = mergeValuesWithDefaults(
2335
2374
  docResult.data.document._values,
2336
- {
2337
- includeCollection: true,
2338
- includeTemplate: typeof collection.templates !== "undefined"
2339
- },
2340
2375
  topLevelDefaults
2341
2376
  );
2377
+ const params = tinaSchema.transformPayload(collection.name, values);
2342
2378
  const mutation = `mutation($collection: String!, $relativePath: String!, $params: DocumentUpdateMutation!) {
2343
2379
  updateDocument(
2344
2380
  collection: $collection,
@@ -2368,46 +2404,8 @@ var auditDocuments = async (args) => {
2368
2404
  }
2369
2405
  return error;
2370
2406
  };
2371
- var transformDocumentIntoMutationRequestPayload = (document, instructions, defaults) => {
2372
- const { _collection, __typename, _template, ...rest } = document;
2373
- const params = transformParams(rest);
2374
- const paramsWithTemplate = instructions.includeTemplate ? { [_template]: params } : params;
2375
- return instructions.includeCollection ? { [_collection]: { ...defaults, ...filterObject(paramsWithTemplate) } } : { ...defaults, ...filterObject(paramsWithTemplate) };
2376
- };
2377
- var transformParams = (data) => {
2378
- if (["string", "number", "boolean"].includes(typeof data)) {
2379
- return data;
2380
- }
2381
- if (Array.isArray(data)) {
2382
- return data.map((item) => transformParams(item));
2383
- }
2384
- try {
2385
- (0, import_graphql12.assertShape)(
2386
- data,
2387
- (yup) => yup.object({ _template: yup.string().required() })
2388
- );
2389
- const { _template, __typename, ...rest } = data;
2390
- const nested = transformParams(rest);
2391
- return { [_template]: nested };
2392
- } catch (e) {
2393
- if (e.message === "Failed to assertShape - _template is a required field") {
2394
- if (!data) {
2395
- return void 0;
2396
- return [];
2397
- }
2398
- const accum = {};
2399
- Object.entries(data).map(([keyName, value]) => {
2400
- accum[keyName] = transformParams(value);
2401
- });
2402
- return accum;
2403
- } else {
2404
- if (!data) {
2405
- return void 0;
2406
- return [];
2407
- }
2408
- throw e;
2409
- }
2410
- }
2407
+ var mergeValuesWithDefaults = (document, defaults) => {
2408
+ return { ...defaults, ...filterObject(document) };
2411
2409
  };
2412
2410
  function filterObject(obj) {
2413
2411
  const ret = {};
@@ -2416,7 +2414,7 @@ function filterObject(obj) {
2416
2414
  }
2417
2415
 
2418
2416
  // src/next/commands/audit-command/index.ts
2419
- var import_graphql14 = require("@tinacms/graphql");
2417
+ var import_graphql13 = require("@tinacms/graphql");
2420
2418
  var AuditCommand = class extends import_clipanion3.Command {
2421
2419
  constructor() {
2422
2420
  super(...arguments);
@@ -2435,6 +2433,9 @@ var AuditCommand = class extends import_clipanion3.Command {
2435
2433
  this.noTelemetry = import_clipanion3.Option.Boolean("--noTelemetry", false, {
2436
2434
  description: "Disable anonymous telemetry that is collected"
2437
2435
  });
2436
+ this.datalayerPort = import_clipanion3.Option.String("--datalayer-port", "9000", {
2437
+ description: "Specify a port to run the datalayer server on. (default 4001)"
2438
+ });
2438
2439
  }
2439
2440
  async catch(error) {
2440
2441
  logger.error("Error occured during tinacms audit");
@@ -2444,7 +2445,7 @@ var AuditCommand = class extends import_clipanion3.Command {
2444
2445
  process.exit(1);
2445
2446
  }
2446
2447
  async execute() {
2447
- const configManager = new ConfigManager(this.rootPath);
2448
+ const configManager = new ConfigManager({ rootPath: this.rootPath });
2448
2449
  logger.info("Starting Tina Audit");
2449
2450
  try {
2450
2451
  await configManager.processConfig();
@@ -2452,12 +2453,12 @@ var AuditCommand = class extends import_clipanion3.Command {
2452
2453
  logger.error(e.message);
2453
2454
  process.exit(1);
2454
2455
  }
2455
- createDBServer();
2456
+ createDBServer(Number(this.datalayerPort));
2456
2457
  const database = await createAndInitializeDatabase(
2457
2458
  configManager,
2458
- this.clean ? void 0 : new import_graphql14.AuditFileSystemBridge(configManager.rootPath)
2459
+ this.clean ? void 0 : new import_graphql13.AuditFileSystemBridge(configManager.rootPath)
2459
2460
  );
2460
- const { tinaSchema, graphQLSchema } = await (0, import_graphql13.buildSchema)(
2461
+ const { tinaSchema, graphQLSchema } = await (0, import_graphql12.buildSchema)(
2461
2462
  database,
2462
2463
  configManager.config
2463
2464
  );
@@ -2842,6 +2843,13 @@ var configExamples = {
2842
2843
  jekyll: other
2843
2844
  };
2844
2845
 
2846
+ // src/cmds/forestry-migrate/index.ts
2847
+ var import_fs_extra7 = __toESM(require("fs-extra"));
2848
+ var import_path8 = __toESM(require("path"));
2849
+ var import_js_yaml2 = __toESM(require("js-yaml"));
2850
+ var import_minimatch = __toESM(require("minimatch"));
2851
+ var import_graphql14 = require("@tinacms/graphql");
2852
+
2845
2853
  // src/cmds/forestry-migrate/util/index.ts
2846
2854
  var import_fs_extra6 = __toESM(require("fs-extra"));
2847
2855
  var import_path7 = __toESM(require("path"));
@@ -2855,28 +2863,29 @@ var ErrorSingleton = class {
2855
2863
  static getInstance() {
2856
2864
  if (!ErrorSingleton.instance) {
2857
2865
  ErrorSingleton.instance = new ErrorSingleton();
2858
- ErrorSingleton.instance.allErrorNames = [];
2866
+ ErrorSingleton.instance.collectionNameErrors = [];
2859
2867
  }
2860
2868
  return ErrorSingleton.instance;
2861
2869
  }
2862
2870
  addErrorName(error) {
2863
- this.allErrorNames.push(error);
2871
+ this.collectionNameErrors.push(error);
2864
2872
  }
2865
- printNameErrors() {
2866
- logger.error(
2867
- dangerText("ERROR: TinaCMS only supports alphanumeric field names")
2868
- );
2869
- logger.error(
2870
- `If you wish to edit any of the following fields or template names you will have to update your content and code to use the new name. See ${linkText(
2871
- "https://tina.io/docs/forestry/common-errors/#migrating-fields-with-non-alphanumeric-characters"
2872
- )} for more information.`
2873
- );
2874
- logger.error("The following template and field names have been renamed:`");
2875
- this.allErrorNames.forEach((error) => {
2873
+ printCollectionNameErrors() {
2874
+ var _a;
2875
+ if ((_a = this.collectionNameErrors) == null ? void 0 : _a.length) {
2876
2876
  logger.error(
2877
- `- Content that uses ${error.template}.yaml: ${error.name} -> ${error.newName}`
2877
+ dangerText("ERROR: TinaCMS only supports alphanumeric template names")
2878
2878
  );
2879
- });
2879
+ logger.error("The following templates have been renamed:");
2880
+ this.collectionNameErrors.forEach((error) => {
2881
+ logger.error(`- ${error.template}.yaml -> ${error.newName}`);
2882
+ });
2883
+ logger.error(
2884
+ `If you wish to edit any of the following templates, you will have to update your content and code to use the new name. See ${linkText(
2885
+ "https://tina.io/docs/forestry/common-errors/#migrating-fields-with-non-alphanumeric-characters"
2886
+ )} for more information.`
2887
+ );
2888
+ }
2880
2889
  }
2881
2890
  };
2882
2891
 
@@ -2982,11 +2991,12 @@ var FrontmatterTemplateSchema = import_zod.default.object({
2982
2991
  });
2983
2992
  var transformForestryFieldsToTinaFields = ({
2984
2993
  fields,
2985
- rootPath,
2994
+ pathToForestryConfig,
2986
2995
  template,
2987
2996
  skipBlocks = false
2988
2997
  }) => {
2989
2998
  const tinaFields = [];
2999
+ const blockFields = [];
2990
3000
  fields == null ? void 0 : fields.forEach((forestryField2) => {
2991
3001
  var _a, _b, _c, _d;
2992
3002
  if (forestryField2.name === "menu") {
@@ -3054,6 +3064,14 @@ var transformForestryFieldsToTinaFields = ({
3054
3064
  label: forestryField2.label
3055
3065
  };
3056
3066
  break;
3067
+ case "image_gallery":
3068
+ field = {
3069
+ type: "image",
3070
+ ...getTinaFieldsFromName(forestryField2.name),
3071
+ label: forestryField2.label,
3072
+ list: true
3073
+ };
3074
+ break;
3057
3075
  case "select":
3058
3076
  if ((_a = forestryField2.config) == null ? void 0 : _a.options) {
3059
3077
  field = {
@@ -3099,7 +3117,7 @@ var transformForestryFieldsToTinaFields = ({
3099
3117
  label: forestryField2.label,
3100
3118
  fields: transformForestryFieldsToTinaFields({
3101
3119
  fields: forestryField2.fields,
3102
- rootPath,
3120
+ pathToForestryConfig,
3103
3121
  template,
3104
3122
  skipBlocks
3105
3123
  })
@@ -3114,20 +3132,22 @@ var transformForestryFieldsToTinaFields = ({
3114
3132
  fields: transformForestryFieldsToTinaFields({
3115
3133
  fields: forestryField2.fields,
3116
3134
  template,
3117
- rootPath,
3135
+ pathToForestryConfig,
3118
3136
  skipBlocks
3119
3137
  })
3120
3138
  };
3121
3139
  break;
3122
3140
  case "blocks":
3123
- if (skipBlocks)
3141
+ if (skipBlocks) {
3142
+ blockFields.push(forestryField2.name);
3124
3143
  break;
3144
+ }
3125
3145
  const templates = [];
3126
3146
  forestryField2 == null ? void 0 : forestryField2.template_types.forEach((tem) => {
3127
3147
  const { fields: fields2, template: template2 } = getFieldsFromTemplates({
3128
3148
  tem,
3129
3149
  skipBlocks: true,
3130
- rootPath: process.cwd()
3150
+ pathToForestryConfig
3131
3151
  });
3132
3152
  const t = {
3133
3153
  fields: fields2,
@@ -3144,7 +3164,6 @@ var transformForestryFieldsToTinaFields = ({
3144
3164
  templates
3145
3165
  };
3146
3166
  break;
3147
- case "image_gallery":
3148
3167
  case "include":
3149
3168
  logger.info(
3150
3169
  warnText(
@@ -3166,11 +3185,22 @@ var transformForestryFieldsToTinaFields = ({
3166
3185
  tinaFields.push(field);
3167
3186
  }
3168
3187
  });
3188
+ if (blockFields.length > 0) {
3189
+ logger.info(
3190
+ warnText(
3191
+ `Skipping blocks field${blockFields.length > 1 ? "s" : ""}: ${blockFields.map((b) => `"${b}"`).join(
3192
+ ", "
3193
+ )}" in ${template}.yaml. Blocks fields need to be manually imported: ${linkText(
3194
+ "https://tina.io/docs/forestry/common-errors/#migrating-blocks"
3195
+ )}`
3196
+ )
3197
+ );
3198
+ }
3169
3199
  return tinaFields;
3170
3200
  };
3171
- var getFieldsFromTemplates = ({ tem, rootPath, skipBlocks = false }) => {
3201
+ var getFieldsFromTemplates = ({ tem, pathToForestryConfig, skipBlocks = true }) => {
3172
3202
  const templatePath = import_path7.default.join(
3173
- rootPath,
3203
+ pathToForestryConfig,
3174
3204
  ".forestry",
3175
3205
  "front_matter",
3176
3206
  "templates",
@@ -3190,7 +3220,7 @@ var getFieldsFromTemplates = ({ tem, rootPath, skipBlocks = false }) => {
3190
3220
  const template = parseTemplates({ val: templateObj });
3191
3221
  const fields = transformForestryFieldsToTinaFields({
3192
3222
  fields: template.fields,
3193
- rootPath,
3223
+ pathToForestryConfig,
3194
3224
  template: tem,
3195
3225
  skipBlocks
3196
3226
  });
@@ -3200,25 +3230,12 @@ var parseTemplates = ({ val }) => {
3200
3230
  const template = FrontmatterTemplateSchema.parse(val);
3201
3231
  return template;
3202
3232
  };
3203
- var hasForestryConfig = async ({ rootPath }) => {
3204
- const forestryPath = import_path7.default.join(rootPath, ".forestry", "settings.yml");
3205
- const exists = await import_fs_extra6.default.pathExists(forestryPath);
3206
- return {
3207
- path: forestryPath,
3208
- exists
3209
- };
3210
- };
3211
3233
  var parseSections = ({ val }) => {
3212
3234
  const schema = forestryConfigSchema.parse(val);
3213
3235
  return schema;
3214
3236
  };
3215
3237
 
3216
3238
  // src/cmds/forestry-migrate/index.ts
3217
- var import_fs_extra7 = __toESM(require("fs-extra"));
3218
- var import_path8 = __toESM(require("path"));
3219
- var import_js_yaml2 = __toESM(require("js-yaml"));
3220
- var import_minimatch = __toESM(require("minimatch"));
3221
- var import_graphql15 = require("@tinacms/graphql");
3222
3239
  var BODY_FIELD = {
3223
3240
  type: "rich-text",
3224
3241
  name: "body",
@@ -3229,18 +3246,34 @@ var BODY_FIELD = {
3229
3246
  var stringifyLabel = (label) => {
3230
3247
  return label.replace(/[^a-zA-Z0-9]/g, "_").toLowerCase();
3231
3248
  };
3232
- var generateAllCollections = async ({
3233
- rootPath
3249
+ var transformForestryMatchToTinaMatch = (match) => {
3250
+ var _a, _b;
3251
+ const newMatch = (_b = (_a = match.replace(" ", "").replace(/\.?(mdx|md|json|yaml|yml|toml)/g, "")) == null ? void 0 : _a.replace(/\..*$/g, "")) == null ? void 0 : _b.replace("{}", "");
3252
+ if (match !== newMatch) {
3253
+ logger.warn(`Warning: Match ${match} was transformed to ${newMatch}`);
3254
+ }
3255
+ return newMatch;
3256
+ };
3257
+ function checkExt(ext) {
3258
+ const extReal = ext.replace(".", "");
3259
+ if (["mdx", "md", "json", "yaml", "yml", "toml"].includes(extReal)) {
3260
+ return extReal;
3261
+ } else {
3262
+ return false;
3263
+ }
3264
+ }
3265
+ var generateAllTemplates = async ({
3266
+ pathToForestryConfig
3234
3267
  }) => {
3235
3268
  const allTemplates = (await import_fs_extra7.default.readdir(
3236
- import_path8.default.join(rootPath, ".forestry", "front_matter", "templates")
3269
+ import_path8.default.join(pathToForestryConfig, ".forestry", "front_matter", "templates")
3237
3270
  )).map((tem) => import_path8.default.basename(tem, ".yml"));
3238
3271
  const templateMap = /* @__PURE__ */ new Map();
3239
3272
  const proms = allTemplates.map(async (tem) => {
3240
3273
  try {
3241
3274
  const { fields, templateObj } = getFieldsFromTemplates({
3242
3275
  tem,
3243
- rootPath
3276
+ pathToForestryConfig
3244
3277
  });
3245
3278
  templateMap.set(tem, { fields, templateObj });
3246
3279
  } catch (e) {
@@ -3252,158 +3285,176 @@ var generateAllCollections = async ({
3252
3285
  await Promise.all(proms);
3253
3286
  return templateMap;
3254
3287
  };
3255
- var generateCollections = async ({
3256
- forestryPath,
3257
- rootPath
3258
- }) => {
3259
- const templateMap = await generateAllCollections({ rootPath });
3260
- const forestryConfig = await import_fs_extra7.default.readFile(forestryPath);
3261
- const forestryYaml = import_js_yaml2.default.load(forestryConfig.toString());
3262
- const forestrySchema = parseSections({ val: forestryYaml });
3263
- const collections = [];
3264
- const sections = forestrySchema.sections;
3265
- for (let index = 0; index < sections.length; index++) {
3266
- const section = sections[index];
3288
+ var generateCollectionFromForestrySection = (section, templateMap) => {
3289
+ if (section.read_only)
3290
+ return;
3291
+ {
3267
3292
  if (section.read_only)
3268
3293
  return;
3269
- switch (section.type) {
3270
- case "directory":
3271
- const forestryTemplates = (section == null ? void 0 : section.templates) || [];
3272
- if (forestryTemplates.length === 0 && section.create === "all") {
3273
- for (let templateKey of templateMap.keys()) {
3274
- const { templateObj } = templateMap.get(templateKey);
3275
- const pages = templateObj == null ? void 0 : templateObj.pages;
3276
- if (pages) {
3277
- if (pages.some(
3278
- (page) => (0, import_minimatch.default)(page, section.path + "/" + section.match)
3279
- )) {
3280
- forestryTemplates.push(templateKey);
3281
- }
3294
+ const baseCollection = {
3295
+ label: section.label,
3296
+ name: stringifyLabel(section.label),
3297
+ path: section.path
3298
+ };
3299
+ if (section.match) {
3300
+ baseCollection.match = {
3301
+ ...(baseCollection == null ? void 0 : baseCollection.match) || {},
3302
+ include: transformForestryMatchToTinaMatch(section.match)
3303
+ };
3304
+ }
3305
+ if (section.exclude) {
3306
+ baseCollection.match = {
3307
+ ...(baseCollection == null ? void 0 : baseCollection.match) || {},
3308
+ exclude: transformForestryMatchToTinaMatch(section.exclude)
3309
+ };
3310
+ }
3311
+ if (section.type === "directory") {
3312
+ const forestryTemplates = (section == null ? void 0 : section.templates) || [];
3313
+ if (forestryTemplates.length === 0 && section.create === "all") {
3314
+ for (let templateKey of templateMap.keys()) {
3315
+ const { templateObj } = templateMap.get(templateKey);
3316
+ const pages = templateObj == null ? void 0 : templateObj.pages;
3317
+ if (pages) {
3318
+ if (pages.some(
3319
+ (page) => (0, import_minimatch.default)(page, section.path + "/" + section.match)
3320
+ )) {
3321
+ forestryTemplates.push(templateKey);
3282
3322
  }
3283
3323
  }
3284
3324
  }
3285
- if (((forestryTemplates == null ? void 0 : forestryTemplates.length) || 0) > 1) {
3286
- const templates = [];
3287
- forestryTemplates.forEach((tem) => {
3288
- var _a;
3289
- try {
3290
- const { fields, templateObj } = templateMap.get(tem);
3291
- templates.push({
3292
- fields: [BODY_FIELD, ...fields],
3293
- label: tem,
3294
- name: stringifyLabel(tem)
3295
- });
3296
- (_a = templateObj == null ? void 0 : templateObj.pages) == null ? void 0 : _a.forEach((page) => {
3297
- try {
3298
- const filePath = import_path8.default.join(rootPath, page);
3299
- const extname = import_path8.default.extname(filePath);
3300
- const fileContent = import_fs_extra7.default.readFileSync(filePath).toString();
3301
- const content2 = (0, import_graphql15.parseFile)(
3302
- fileContent,
3303
- extname,
3304
- (yup) => yup.object({})
3305
- );
3306
- const newContent = {
3307
- _template: stringifyLabel(tem),
3308
- ...content2
3309
- };
3310
- import_fs_extra7.default.writeFileSync(
3311
- filePath,
3312
- (0, import_graphql15.stringifyFile)(newContent, extname, true)
3313
- );
3314
- } catch (error) {
3315
- console.log("Error updating file", page);
3316
- }
3317
- });
3318
- } catch (e) {
3319
- console.log("Error parsing template ", tem);
3320
- console.error(e);
3321
- }
3322
- });
3323
- const c = {
3324
- label: section.label,
3325
- name: stringifyLabel(section.label),
3326
- path: section.path,
3327
- templates
3325
+ }
3326
+ const c = ((forestryTemplates == null ? void 0 : forestryTemplates.length) || 0) > 1 ? {
3327
+ ...baseCollection,
3328
+ templates: forestryTemplates.map((tem) => {
3329
+ const { fields } = templateMap.get(tem);
3330
+ return {
3331
+ fields: [BODY_FIELD, ...fields],
3332
+ label: tem,
3333
+ name: stringifyLabel(tem)
3328
3334
  };
3329
- if ((section == null ? void 0 : section.create) === "none") {
3330
- c.ui = {
3331
- ...c.ui,
3332
- allowedActions: {
3333
- create: false
3334
- }
3335
- };
3336
- }
3337
- collections.push(c);
3338
- } else {
3339
- const fields = [BODY_FIELD];
3340
- forestryTemplates == null ? void 0 : forestryTemplates.forEach((tem) => {
3341
- var _a;
3335
+ })
3336
+ } : {
3337
+ ...baseCollection,
3338
+ fields: [
3339
+ BODY_FIELD,
3340
+ ...(forestryTemplates || []).flatMap((tem) => {
3342
3341
  try {
3343
- const { fields: additionalFields, templateObj } = templateMap.get(tem);
3344
- fields.push(...additionalFields);
3345
- (_a = templateObj == null ? void 0 : templateObj.pages) == null ? void 0 : _a.forEach((page) => {
3346
- try {
3347
- const filePath = import_path8.default.join(rootPath, page);
3348
- const extname = import_path8.default.extname(filePath);
3349
- const fileContent = import_fs_extra7.default.readFileSync(filePath).toString();
3350
- const content2 = (0, import_graphql15.parseFile)(
3351
- fileContent,
3352
- extname,
3353
- (yup) => yup.object({})
3354
- );
3355
- const newContent = {
3356
- _template: stringifyLabel(tem),
3357
- ...content2
3358
- };
3359
- import_fs_extra7.default.writeFileSync(
3360
- filePath,
3361
- (0, import_graphql15.stringifyFile)(newContent, extname, true)
3362
- );
3363
- } catch (error) {
3364
- logger.log("Error updating file", page);
3365
- }
3366
- });
3342
+ const { fields: additionalFields } = templateMap.get(tem);
3343
+ return additionalFields;
3367
3344
  } catch (e) {
3368
3345
  logger.log("Error parsing template ", tem);
3369
- console.error(e);
3346
+ return [];
3370
3347
  }
3371
- });
3372
- const c = {
3373
- label: section.label,
3374
- name: stringifyLabel(section.label),
3375
- path: section.path,
3376
- fields
3377
- };
3378
- if ((section == null ? void 0 : section.create) === "none") {
3379
- c.ui = {
3380
- ...c.ui,
3381
- allowedActions: {
3382
- create: false
3383
- }
3384
- };
3348
+ })
3349
+ ]
3350
+ };
3351
+ if ((section == null ? void 0 : section.create) === "none") {
3352
+ c.ui = {
3353
+ ...c.ui,
3354
+ allowedActions: {
3355
+ create: false
3385
3356
  }
3386
- collections.push(c);
3357
+ };
3358
+ }
3359
+ return c;
3360
+ } else if (section.type === "document") {
3361
+ const filePath = section.path;
3362
+ const extname = import_path8.default.extname(filePath);
3363
+ const fileName = import_path8.default.basename(filePath, extname);
3364
+ const dir = import_path8.default.dirname(filePath);
3365
+ const ext = checkExt(extname);
3366
+ if (ext) {
3367
+ const fields = [];
3368
+ if (ext === "md" || ext === "mdx") {
3369
+ fields.push(BODY_FIELD);
3387
3370
  }
3388
- break;
3389
- case "document":
3390
- console.log(
3371
+ for (let currentTemplateName of templateMap.keys()) {
3372
+ const { templateObj, fields: additionalFields } = templateMap.get(currentTemplateName);
3373
+ const pages = (templateObj == null ? void 0 : templateObj.pages) || [];
3374
+ if (pages.includes(section.path)) {
3375
+ fields.push(...additionalFields);
3376
+ break;
3377
+ }
3378
+ }
3379
+ if (fields.length === 0) {
3380
+ fields.push({
3381
+ name: "dummy",
3382
+ label: "Dummy field",
3383
+ type: "string",
3384
+ description: "This is a dummy field, please replace it with the fields you want to edit. See https://tina.io/docs/schema/ for more info"
3385
+ });
3386
+ logger.warn(
3387
+ warnText(
3388
+ `No fields found for ${section.path}. Please add the fields you want to edit to the ${section.label} collection in the config file.`
3389
+ )
3390
+ );
3391
+ }
3392
+ return {
3393
+ ...baseCollection,
3394
+ path: dir,
3395
+ format: ext,
3396
+ ui: {
3397
+ allowedActions: {
3398
+ create: false,
3399
+ delete: false
3400
+ }
3401
+ },
3402
+ match: {
3403
+ include: fileName
3404
+ },
3405
+ fields
3406
+ };
3407
+ } else {
3408
+ logger.log(
3391
3409
  warnText(
3392
- `Single Document are not supported in TinaCMS yet. Skipping section ${section.label} (${section.path})`
3410
+ `Error: document section has an unsupported file extension: ${extname} in ${section.path}`
3393
3411
  )
3394
3412
  );
3395
- break;
3413
+ }
3396
3414
  }
3397
3415
  }
3398
- return collections;
3416
+ };
3417
+ var generateCollections = async ({
3418
+ pathToForestryConfig
3419
+ }) => {
3420
+ const templateMap = await generateAllTemplates({ pathToForestryConfig });
3421
+ const forestryConfig = await import_fs_extra7.default.readFile(
3422
+ import_path8.default.join(pathToForestryConfig, ".forestry", "settings.yml")
3423
+ );
3424
+ rewriteTemplateKeysInDocs(templateMap, pathToForestryConfig);
3425
+ return parseSections({ val: import_js_yaml2.default.load(forestryConfig.toString()) }).sections.map(
3426
+ (section) => generateCollectionFromForestrySection(section, templateMap)
3427
+ ).filter((c) => c !== void 0);
3428
+ };
3429
+ var rewriteTemplateKeysInDocs = (templateMap, rootPath) => {
3430
+ var _a;
3431
+ for (const templateKey of templateMap.keys()) {
3432
+ const { templateObj } = templateMap.get(templateKey);
3433
+ (_a = templateObj == null ? void 0 : templateObj.pages) == null ? void 0 : _a.forEach((page) => {
3434
+ try {
3435
+ const filePath = import_path8.default.join(page);
3436
+ const extname = import_path8.default.extname(filePath);
3437
+ const fileContent = import_fs_extra7.default.readFileSync(filePath).toString();
3438
+ const content2 = (0, import_graphql14.parseFile)(fileContent, extname, (yup) => yup.object({}));
3439
+ const newContent = {
3440
+ _template: stringifyLabel(templateKey),
3441
+ ...content2
3442
+ };
3443
+ import_fs_extra7.default.writeFileSync(filePath, (0, import_graphql14.stringifyFile)(newContent, extname, true));
3444
+ } catch (error) {
3445
+ console.log(
3446
+ dangerText("Error updating template -> _template in ", page)
3447
+ );
3448
+ }
3449
+ });
3450
+ }
3399
3451
  };
3400
3452
 
3401
3453
  // src/cmds/init/index.ts
3402
3454
  async function initStaticTina({
3403
- rootPath,
3455
+ pathToForestryConfig,
3404
3456
  noTelemetry
3405
3457
  }) {
3406
- const baseDir = rootPath;
3407
3458
  logger.level = "info";
3408
3459
  const clientId = await chooseClientId();
3409
3460
  let token = null;
@@ -3414,17 +3465,18 @@ async function initStaticTina({
3414
3465
  const framework = await chooseFramework();
3415
3466
  const usingTypescript = await chooseTypescript();
3416
3467
  const publicFolder = await choosePublicFolder({ framework });
3417
- const forestryPath = await hasForestryConfig({ rootPath });
3418
3468
  let collections;
3419
- if (forestryPath.exists) {
3469
+ const hasForestryConfig = await import_fs_extra8.default.pathExists(
3470
+ import_path9.default.join(pathToForestryConfig, ".forestry", "settings.yml")
3471
+ );
3472
+ if (hasForestryConfig) {
3420
3473
  collections = await forestryMigrate({
3421
- forestryPath: forestryPath.path,
3422
- rootPath
3474
+ pathToForestryConfig
3423
3475
  });
3424
3476
  }
3425
3477
  await reportTelemetry({
3426
3478
  usingTypescript,
3427
- hasForestryConfig: forestryPath.exists,
3479
+ hasForestryConfig,
3428
3480
  noTelemetry
3429
3481
  });
3430
3482
  const hasPackageJSON = await import_fs_extra8.default.pathExistsSync("package.json");
@@ -3433,31 +3485,34 @@ async function initStaticTina({
3433
3485
  }
3434
3486
  const hasGitignore = await import_fs_extra8.default.pathExistsSync(".gitignore");
3435
3487
  if (!hasGitignore) {
3436
- await createGitignore({ baseDir });
3488
+ await createGitignore({ baseDir: "" });
3437
3489
  } else {
3438
3490
  const hasNodeModulesIgnored = await checkGitignoreForNodeModules({
3439
- baseDir
3491
+ baseDir: ""
3440
3492
  });
3441
3493
  if (!hasNodeModulesIgnored) {
3442
- await addNodeModulesToGitignore({ baseDir });
3494
+ await addNodeModulesToGitignore({ baseDir: "" });
3443
3495
  }
3444
3496
  }
3445
3497
  await addDependencies(packageManager);
3446
3498
  await addConfigFile({
3447
- publicFolder,
3448
- baseDir,
3499
+ publicFolder: import_path9.default.join(
3500
+ import_path9.default.relative(process.cwd(), pathToForestryConfig),
3501
+ publicFolder
3502
+ ),
3503
+ baseDir: "",
3449
3504
  usingTypescript,
3450
3505
  framework,
3451
3506
  collections,
3452
3507
  token,
3453
3508
  clientId
3454
3509
  });
3455
- if (!forestryPath.exists) {
3456
- await addContentFile({ baseDir });
3510
+ if (!hasForestryConfig) {
3511
+ await addContentFile({ baseDir: "" });
3457
3512
  }
3458
3513
  if (framework.reactive) {
3459
3514
  await addReactiveFile[framework.name]({
3460
- baseDir,
3515
+ baseDir: "",
3461
3516
  framework,
3462
3517
  usingTypescript
3463
3518
  });
@@ -3549,48 +3604,30 @@ var chooseFramework = async () => {
3549
3604
  return option["selection"];
3550
3605
  };
3551
3606
  var forestryMigrate = async ({
3552
- forestryPath,
3553
- rootPath
3607
+ pathToForestryConfig
3554
3608
  }) => {
3555
- logger.info(
3556
- `It looks like you have a ${focusText(
3557
- ".forestry/settings.yml"
3558
- )} file in your project.`
3559
- );
3560
- logger.info(
3561
- `This migration will update some of your content to match tina. Please ${focusText(
3562
- "save a backup of your content"
3563
- )} before doing this migration. (This can be done with git)`
3609
+ logger.info(`Forestry.io configuration found.`);
3610
+ const disclaimer = logText(
3611
+ `Note: This migration will update some of your content to match tina. Please save a backup of your content before doing this migration. (This can be done with git)`
3564
3612
  );
3565
3613
  const option = await (0, import_prompts2.default)({
3566
3614
  name: "selection",
3567
3615
  type: "confirm",
3568
3616
  initial: true,
3569
- message: `Please note that this is a beta version and may contain some issues
3570
- Would you like to migrate your Forestry templates?
3571
- ${logText(
3572
- "Note: This migration will not be perfect, but it will get you started."
3573
- )}`
3617
+ message: `Would you like to migrate your Forestry templates?
3618
+ ${disclaimer}`
3574
3619
  });
3575
3620
  if (!option["selection"]) {
3576
3621
  return null;
3577
3622
  }
3578
- const delay = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
3579
- await spin({
3580
- waitFor: async () => {
3581
- await delay(2e3);
3582
- },
3583
- text: ""
3584
- });
3585
3623
  const collections = await generateCollections({
3586
- forestryPath,
3587
- rootPath
3624
+ pathToForestryConfig
3588
3625
  });
3589
- ErrorSingleton.getInstance().printNameErrors();
3626
+ ErrorSingleton.getInstance().printCollectionNameErrors();
3590
3627
  return JSON.stringify(collections, null, 2);
3591
3628
  };
3592
3629
  var reportTelemetry = async ({
3593
- hasForestryConfig: hasForestryConfig2,
3630
+ hasForestryConfig,
3594
3631
  noTelemetry,
3595
3632
  usingTypescript
3596
3633
  }) => {
@@ -3603,7 +3640,7 @@ var reportTelemetry = async ({
3603
3640
  event: {
3604
3641
  name: "tinacms:cli:init:invoke",
3605
3642
  schemaFileType,
3606
- hasForestryConfig: hasForestryConfig2
3643
+ hasForestryConfig
3607
3644
  }
3608
3645
  });
3609
3646
  };
@@ -3788,8 +3825,8 @@ function execShellCommand(cmd) {
3788
3825
  var InitCommand = class extends import_clipanion4.Command {
3789
3826
  constructor() {
3790
3827
  super(...arguments);
3791
- this.rootPath = import_clipanion4.Option.String("--rootPath", {
3792
- description: "Specify the root directory to run the CLI from"
3828
+ this.pathToForestryConfig = import_clipanion4.Option.String("--forestryPath", {
3829
+ description: "Specify the relative path to the .forestry directory, if importing an existing forestry site."
3793
3830
  });
3794
3831
  this.noTelemetry = import_clipanion4.Option.Boolean("--noTelemetry", false, {
3795
3832
  description: "Disable anonymous telemetry that is collected"
@@ -3802,7 +3839,7 @@ var InitCommand = class extends import_clipanion4.Command {
3802
3839
  }
3803
3840
  async execute() {
3804
3841
  await initStaticTina({
3805
- rootPath: this.rootPath || process.cwd(),
3842
+ pathToForestryConfig: this.pathToForestryConfig || process.cwd(),
3806
3843
  noTelemetry: this.noTelemetry
3807
3844
  });
3808
3845
  process.exit();