@sanity/cli 7.10.0 → 7.12.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.
Files changed (174) hide show
  1. package/README.md +31 -22
  2. package/dist/actions/auth/ensureAuthenticated.js +2 -0
  3. package/dist/actions/auth/ensureAuthenticated.js.map +1 -1
  4. package/dist/actions/auth/login/loginInstructions.js +19 -0
  5. package/dist/actions/auth/login/loginInstructions.js.map +1 -0
  6. package/dist/actions/build/buildApp.js +10 -7
  7. package/dist/actions/build/buildApp.js.map +1 -1
  8. package/dist/actions/build/buildStudio.js +9 -6
  9. package/dist/actions/build/buildStudio.js.map +1 -1
  10. package/dist/actions/build/types.js.map +1 -1
  11. package/dist/actions/dataset/resolveDataset.js +7 -1
  12. package/dist/actions/dataset/resolveDataset.js.map +1 -1
  13. package/dist/actions/deploy/deployApp.js +205 -157
  14. package/dist/actions/deploy/deployApp.js.map +1 -1
  15. package/dist/actions/deploy/deployChecks.js +1 -1
  16. package/dist/actions/deploy/deployChecks.js.map +1 -1
  17. package/dist/actions/deploy/deployStudio.js +127 -86
  18. package/dist/actions/deploy/deployStudio.js.map +1 -1
  19. package/dist/actions/deploy/resolveDeployTarget.js +5 -9
  20. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  21. package/dist/actions/dev/devAction.js +1 -2
  22. package/dist/actions/dev/devAction.js.map +1 -1
  23. package/dist/actions/dev/servers/getDevServerConfig.js +8 -2
  24. package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
  25. package/dist/actions/graphql/resolveApiGeneration.js +9 -6
  26. package/dist/actions/graphql/resolveApiGeneration.js.map +1 -1
  27. package/dist/actions/init/bootstrapLocalTemplate.js +18 -9
  28. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  29. package/dist/actions/init/createAppCliConfig.js.map +1 -1
  30. package/dist/actions/init/createCliConfig.js.map +1 -1
  31. package/dist/actions/init/initAction.js +23 -15
  32. package/dist/actions/init/initAction.js.map +1 -1
  33. package/dist/actions/manifest/extractCoreAppManifest.js +5 -3
  34. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  35. package/dist/actions/migration/constants.js +10 -0
  36. package/dist/actions/migration/constants.js.map +1 -0
  37. package/dist/actions/migration/ensureApiVersionFormat.js +16 -0
  38. package/dist/actions/migration/ensureApiVersionFormat.js.map +1 -0
  39. package/dist/actions/migration/fileExists.js +13 -0
  40. package/dist/actions/migration/fileExists.js.map +1 -0
  41. package/dist/actions/migration/prettyMutationFormatter.js +155 -0
  42. package/dist/actions/migration/prettyMutationFormatter.js.map +1 -0
  43. package/dist/actions/migration/resolveMigrationScript.js +75 -0
  44. package/dist/actions/migration/resolveMigrationScript.js.map +1 -0
  45. package/dist/actions/migration/resolveMigrations.js +50 -0
  46. package/dist/actions/migration/resolveMigrations.js.map +1 -0
  47. package/dist/actions/migration/templates/index.js +7 -0
  48. package/dist/actions/migration/templates/index.js.map +1 -0
  49. package/dist/actions/migration/templates/minimalAdvanced.js +21 -0
  50. package/dist/actions/migration/templates/minimalAdvanced.js.map +1 -0
  51. package/dist/actions/migration/templates/minimalSimple.js +61 -0
  52. package/dist/actions/migration/templates/minimalSimple.js.map +1 -0
  53. package/dist/actions/migration/templates/renameField.js +20 -0
  54. package/dist/actions/migration/templates/renameField.js.map +1 -0
  55. package/dist/actions/migration/templates/renameType.js +19 -0
  56. package/dist/actions/migration/templates/renameType.js.map +1 -0
  57. package/dist/actions/migration/templates/stringToPTE.js +32 -0
  58. package/dist/actions/migration/templates/stringToPTE.js.map +1 -0
  59. package/dist/actions/migration/tree.js +111 -0
  60. package/dist/actions/migration/tree.js.map +1 -0
  61. package/dist/actions/preview/previewAction.js +33 -1
  62. package/dist/actions/preview/previewAction.js.map +1 -1
  63. package/dist/actions/schema/listSchemas.js +6 -4
  64. package/dist/actions/schema/listSchemas.js.map +1 -1
  65. package/dist/actions/tokens/validateRole.js +2 -1
  66. package/dist/actions/tokens/validateRole.js.map +1 -1
  67. package/dist/actions/undeploy/runUndeploy.js +13 -4
  68. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  69. package/dist/commands/backups/disable.js +5 -1
  70. package/dist/commands/backups/disable.js.map +1 -1
  71. package/dist/commands/backups/download.js +30 -6
  72. package/dist/commands/backups/download.js.map +1 -1
  73. package/dist/commands/backups/enable.js +5 -1
  74. package/dist/commands/backups/enable.js.map +1 -1
  75. package/dist/commands/backups/list.js +5 -1
  76. package/dist/commands/backups/list.js.map +1 -1
  77. package/dist/commands/cors/add.js +15 -7
  78. package/dist/commands/cors/add.js.map +1 -1
  79. package/dist/commands/cors/delete.js +6 -1
  80. package/dist/commands/cors/delete.js.map +1 -1
  81. package/dist/commands/datasets/alias/create.js +25 -18
  82. package/dist/commands/datasets/alias/create.js.map +1 -1
  83. package/dist/commands/datasets/alias/delete.js +15 -8
  84. package/dist/commands/datasets/alias/delete.js.map +1 -1
  85. package/dist/commands/datasets/alias/link.js +39 -17
  86. package/dist/commands/datasets/alias/link.js.map +1 -1
  87. package/dist/commands/datasets/alias/unlink.js +23 -2
  88. package/dist/commands/datasets/alias/unlink.js.map +1 -1
  89. package/dist/commands/datasets/copy.js +18 -2
  90. package/dist/commands/datasets/copy.js.map +1 -1
  91. package/dist/commands/datasets/create.js +8 -2
  92. package/dist/commands/datasets/create.js.map +1 -1
  93. package/dist/commands/datasets/delete.js +14 -17
  94. package/dist/commands/datasets/delete.js.map +1 -1
  95. package/dist/commands/datasets/embeddings/disable.js +3 -0
  96. package/dist/commands/datasets/embeddings/disable.js.map +1 -1
  97. package/dist/commands/datasets/embeddings/enable.js +5 -2
  98. package/dist/commands/datasets/embeddings/enable.js.map +1 -1
  99. package/dist/commands/datasets/embeddings/status.js +3 -0
  100. package/dist/commands/datasets/embeddings/status.js.map +1 -1
  101. package/dist/commands/datasets/export.js +27 -15
  102. package/dist/commands/datasets/export.js.map +1 -1
  103. package/dist/commands/datasets/import.js +3 -3
  104. package/dist/commands/datasets/import.js.map +1 -1
  105. package/dist/commands/datasets/visibility/get.js +2 -2
  106. package/dist/commands/datasets/visibility/get.js.map +1 -1
  107. package/dist/commands/datasets/visibility/set.js +2 -2
  108. package/dist/commands/datasets/visibility/set.js.map +1 -1
  109. package/dist/commands/docs/read.js +3 -3
  110. package/dist/commands/docs/read.js.map +1 -1
  111. package/dist/commands/documents/create.js +18 -13
  112. package/dist/commands/documents/create.js.map +1 -1
  113. package/dist/commands/documents/delete.js +3 -3
  114. package/dist/commands/documents/delete.js.map +1 -1
  115. package/dist/commands/documents/get.js +3 -3
  116. package/dist/commands/documents/get.js.map +1 -1
  117. package/dist/commands/documents/query.js +3 -3
  118. package/dist/commands/documents/query.js.map +1 -1
  119. package/dist/commands/documents/validate.js +29 -26
  120. package/dist/commands/documents/validate.js.map +1 -1
  121. package/dist/commands/graphql/deploy.js +20 -16
  122. package/dist/commands/graphql/deploy.js.map +1 -1
  123. package/dist/commands/graphql/undeploy.js +15 -18
  124. package/dist/commands/graphql/undeploy.js.map +1 -1
  125. package/dist/commands/hooks/delete.js +2 -2
  126. package/dist/commands/hooks/delete.js.map +1 -1
  127. package/dist/commands/hooks/logs.js +2 -2
  128. package/dist/commands/hooks/logs.js.map +1 -1
  129. package/dist/commands/login.js +2 -1
  130. package/dist/commands/login.js.map +1 -1
  131. package/dist/commands/media/create-aspect.js +20 -8
  132. package/dist/commands/media/create-aspect.js.map +1 -1
  133. package/dist/commands/media/delete-aspect.js +31 -16
  134. package/dist/commands/media/delete-aspect.js.map +1 -1
  135. package/dist/commands/media/deploy-aspect.js +10 -5
  136. package/dist/commands/media/deploy-aspect.js.map +1 -1
  137. package/dist/commands/media/export.js +9 -4
  138. package/dist/commands/media/export.js.map +1 -1
  139. package/dist/commands/media/import.js +6 -1
  140. package/dist/commands/media/import.js.map +1 -1
  141. package/dist/commands/migrations/create.js +150 -0
  142. package/dist/commands/migrations/create.js.map +1 -0
  143. package/dist/commands/migrations/list.js +64 -0
  144. package/dist/commands/migrations/list.js.map +1 -0
  145. package/dist/commands/migrations/run.js +306 -0
  146. package/dist/commands/migrations/run.js.map +1 -0
  147. package/dist/commands/preview.js +1 -0
  148. package/dist/commands/preview.js.map +1 -1
  149. package/dist/commands/projects/create.js +2 -1
  150. package/dist/commands/projects/create.js.map +1 -1
  151. package/dist/commands/schemas/delete.js +23 -2
  152. package/dist/commands/schemas/delete.js.map +1 -1
  153. package/dist/commands/schemas/deploy.js +6 -4
  154. package/dist/commands/schemas/deploy.js.map +1 -1
  155. package/dist/commands/schemas/extract.js +22 -1
  156. package/dist/commands/schemas/extract.js.map +1 -1
  157. package/dist/commands/schemas/list.js +8 -8
  158. package/dist/commands/schemas/list.js.map +1 -1
  159. package/dist/commands/tokens/{add.js → create.js} +25 -18
  160. package/dist/commands/tokens/create.js.map +1 -0
  161. package/dist/commands/tokens/delete.js +41 -23
  162. package/dist/commands/tokens/delete.js.map +1 -1
  163. package/dist/commands/undeploy.js +2 -7
  164. package/dist/commands/undeploy.js.map +1 -1
  165. package/dist/commands/users/invite.js +25 -3
  166. package/dist/commands/users/invite.js.map +1 -1
  167. package/dist/topicAliases.js +3 -0
  168. package/dist/topicAliases.js.map +1 -1
  169. package/dist/util/formatCliErrorMessages.js +5 -0
  170. package/dist/util/formatCliErrorMessages.js.map +1 -0
  171. package/oclif.config.js +5 -1
  172. package/oclif.manifest.json +579 -374
  173. package/package.json +7 -7
  174. package/dist/commands/tokens/add.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/migration/ensureApiVersionFormat.ts"],"sourcesContent":["import {type APIConfig} from '@sanity/migrate'\n\ntype ApiVersion = APIConfig['apiVersion']\n\nconst VERSION_PATTERN = /^v\\d+-\\d+-\\d+$|^vX$/ // Matches version strings like vYYYY-MM-DD or vX\n\n/**\n * Ensures that the provided API version string is in the correct format.\n * If the version does not start with 'v', it will be prefixed with 'v'.\n * If the version does not match the expected pattern, an error will be thrown.\n */\nexport function ensureApiVersionFormat(version: string): ApiVersion {\n const normalizedVersion = version.startsWith('v') ? version : `v${version}`\n\n // Check if the version matches the expected pattern\n if (!VERSION_PATTERN.test(normalizedVersion)) {\n throw new Error(\n `Invalid API version format: ${normalizedVersion}. Expected format: vYYYY-MM-DD or vX`,\n )\n }\n\n return normalizedVersion as ApiVersion\n}\n"],"names":["VERSION_PATTERN","ensureApiVersionFormat","version","normalizedVersion","startsWith","test","Error"],"mappings":"AAIA,MAAMA,kBAAkB,sBAAsB,iDAAiD;;AAE/F;;;;CAIC,GACD,OAAO,SAASC,uBAAuBC,OAAe;IACpD,MAAMC,oBAAoBD,QAAQE,UAAU,CAAC,OAAOF,UAAU,CAAC,CAAC,EAAEA,SAAS;IAE3E,oDAAoD;IACpD,IAAI,CAACF,gBAAgBK,IAAI,CAACF,oBAAoB;QAC5C,MAAM,IAAIG,MACR,CAAC,4BAA4B,EAAEH,kBAAkB,oCAAoC,CAAC;IAE1F;IAEA,OAAOA;AACT"}
@@ -0,0 +1,13 @@
1
+ import { access } from 'node:fs/promises';
2
+ /**
3
+ * Checks if a file exists and can be "accessed".
4
+ * Prone to race conditions, but good enough for our use cases.
5
+ *
6
+ * @param filePath - The path to the file to check
7
+ * @returns A promise that resolves to true if the file exists, false otherwise
8
+ * @internal
9
+ */ export function fileExists(filePath) {
10
+ return access(filePath).then(()=>true, ()=>false);
11
+ }
12
+
13
+ //# sourceMappingURL=fileExists.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/migration/fileExists.ts"],"sourcesContent":["import {access} from 'node:fs/promises'\n\n/**\n * Checks if a file exists and can be \"accessed\".\n * Prone to race conditions, but good enough for our use cases.\n *\n * @param filePath - The path to the file to check\n * @returns A promise that resolves to true if the file exists, false otherwise\n * @internal\n */\nexport function fileExists(filePath: string): Promise<boolean> {\n return access(filePath).then(\n () => true,\n () => false,\n )\n}\n"],"names":["access","fileExists","filePath","then"],"mappings":"AAAA,SAAQA,MAAM,QAAO,mBAAkB;AAEvC;;;;;;;CAOC,GACD,OAAO,SAASC,WAAWC,QAAgB;IACzC,OAAOF,OAAOE,UAAUC,IAAI,CAC1B,IAAM,MACN,IAAM;AAEV"}
@@ -0,0 +1,155 @@
1
+ import { isatty } from 'node:tty';
2
+ import { styleText } from 'node:util';
3
+ import { convertToTree, formatTree, maxKeyLength } from './tree.js';
4
+ const isTty = isatty(1);
5
+ export function prettyFormat({ indentSize = 0, migration, subject }) {
6
+ return (Array.isArray(subject) ? subject : [
7
+ subject
8
+ ]).map((subjectEntry)=>{
9
+ if (subjectEntry.type === 'transaction') {
10
+ return [
11
+ [
12
+ badge('transaction', 'info'),
13
+ subjectEntry.id === undefined ? null : styleText('underline', subjectEntry.id)
14
+ ].filter(Boolean).join(' '),
15
+ indent(prettyFormat({
16
+ indentSize: indentSize,
17
+ migration,
18
+ subject: subjectEntry.mutations
19
+ }))
20
+ ].join('\n\n');
21
+ }
22
+ return prettyFormatMutation({
23
+ indentSize,
24
+ migration,
25
+ subject: subjectEntry
26
+ });
27
+ }).join('\n\n');
28
+ }
29
+ function encodeItemRef(ref) {
30
+ return typeof ref === 'number' ? ref : ref._key;
31
+ }
32
+ function badgeStyle(variant, label) {
33
+ const styles = {
34
+ destructive: styleText([
35
+ 'bgRed',
36
+ 'black',
37
+ 'bold'
38
+ ], label),
39
+ incremental: styleText([
40
+ 'bgGreen',
41
+ 'black',
42
+ 'bold'
43
+ ], label),
44
+ info: styleText([
45
+ 'bgWhite',
46
+ 'black'
47
+ ], label),
48
+ maybeDestructive: styleText([
49
+ 'bgYellow',
50
+ 'black',
51
+ 'bold'
52
+ ], label)
53
+ };
54
+ return styles[variant];
55
+ }
56
+ function badge(label, variant) {
57
+ if (!isTty) {
58
+ return `[${label}]`;
59
+ }
60
+ return badgeStyle(variant, ` ${label} `);
61
+ }
62
+ const mutationImpact = {
63
+ create: 'incremental',
64
+ createIfNotExists: 'incremental',
65
+ createOrReplace: 'maybeDestructive',
66
+ delete: 'destructive',
67
+ patch: 'maybeDestructive'
68
+ };
69
+ function documentId(mutation) {
70
+ if ('id' in mutation) {
71
+ return mutation.id;
72
+ }
73
+ if ('document' in mutation) {
74
+ return mutation.document._id;
75
+ }
76
+ return undefined;
77
+ }
78
+ const listFormatter = new Intl.ListFormat('en-US', {
79
+ type: 'disjunction'
80
+ });
81
+ function mutationHeader(mutation, migration) {
82
+ const mutationType = badge(mutation.type, mutationImpact[mutation.type]);
83
+ const documentType = 'document' in mutation || migration.documentTypes ? badge('document' in mutation ? mutation.document._type : listFormatter.format(migration.documentTypes ?? []), 'info') : null;
84
+ // TODO: Should we list documentType when a mutation can be yielded for any document type?
85
+ return [
86
+ mutationType,
87
+ documentType,
88
+ styleText('underline', documentId(mutation) ?? '')
89
+ ].filter(Boolean).join(' ');
90
+ }
91
+ function prettyFormatMutation({ indentSize = 0, migration, subject }) {
92
+ const lock = 'options' in subject ? styleText('cyan', `(if revision==${subject.options?.ifRevision})`) : '';
93
+ const header = [
94
+ mutationHeader(subject, migration),
95
+ lock
96
+ ].join(' ');
97
+ const padding = ' '.repeat(indentSize);
98
+ if (subject.type === 'create' || subject.type === 'createIfNotExists' || subject.type === 'createOrReplace') {
99
+ return [
100
+ header,
101
+ '\n',
102
+ indent(JSON.stringify(subject.document, null, 2), indentSize)
103
+ ].join('');
104
+ }
105
+ if (subject.type === 'patch') {
106
+ const tree = convertToTree(subject.patches.flat());
107
+ const paddingLength = Math.max(maxKeyLength(tree.children) + 2, 30);
108
+ return [
109
+ header,
110
+ '\n',
111
+ formatTree({
112
+ getMessage: (patch)=>formatPatchMutation(patch),
113
+ indent: padding,
114
+ node: tree.children,
115
+ paddingLength
116
+ })
117
+ ].join('');
118
+ }
119
+ return header;
120
+ }
121
+ function formatPatchMutation(patch) {
122
+ const { op } = patch;
123
+ const formattedType = styleText('bold', op.type);
124
+ if (op.type === 'unset') {
125
+ return `${styleText('red', formattedType)}()`;
126
+ }
127
+ if (op.type === 'diffMatchPatch') {
128
+ return `${styleText('yellow', formattedType)}(${op.value})`;
129
+ }
130
+ if (op.type === 'inc' || op.type === 'dec') {
131
+ return `${styleText('yellow', formattedType)}(${op.amount})`;
132
+ }
133
+ if (op.type === 'set') {
134
+ return `${styleText('yellow', formattedType)}(${JSON.stringify(op.value)})`;
135
+ }
136
+ if (op.type === 'setIfMissing') {
137
+ return `${styleText('green', formattedType)}(${JSON.stringify(op.value)})`;
138
+ }
139
+ if (op.type === 'insert') {
140
+ return `${styleText('green', formattedType)}(${op.position}, ${encodeItemRef(op.referenceItem)}, ${JSON.stringify(op.items)})`;
141
+ }
142
+ if (op.type === 'replace') {
143
+ return `${styleText('yellow', formattedType)}(${encodeItemRef(op.referenceItem)}, ${JSON.stringify(op.items)})`;
144
+ }
145
+ if (op.type === 'truncate') {
146
+ return `${styleText('red', formattedType)}(${op.startIndex}, ${op.endIndex})`;
147
+ }
148
+ throw new Error(`Invalid operation type: ${op.type}`);
149
+ }
150
+ function indent(subject, size = 2) {
151
+ const padding = ' '.repeat(size);
152
+ return subject.split('\n').map((line)=>padding + line).join('\n');
153
+ }
154
+
155
+ //# sourceMappingURL=prettyMutationFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/migration/prettyMutationFormatter.ts"],"sourcesContent":["import {isatty} from 'node:tty'\nimport {styleText} from 'node:util'\n\nimport {type Migration, type Mutation, type NodePatch, type Transaction} from '@sanity/migrate'\nimport {type KeyedSegment} from '@sanity/types'\n\nimport {convertToTree, formatTree, maxKeyLength} from './tree.js'\n\ntype ItemRef = number | string\ntype Impact = 'destructive' | 'incremental' | 'maybeDestructive'\ntype Variant = 'info' | Impact\n\nconst isTty = isatty(1)\n\ninterface FormatterOptions<Subject> {\n migration: Migration\n subject: Subject\n\n indentSize?: number\n}\n\nexport function prettyFormat({\n indentSize = 0,\n migration,\n subject,\n}: FormatterOptions<(Mutation | Transaction)[] | Mutation | Transaction>): string {\n return (Array.isArray(subject) ? subject : [subject])\n .map((subjectEntry) => {\n if (subjectEntry.type === 'transaction') {\n return [\n [\n badge('transaction', 'info'),\n subjectEntry.id === undefined ? null : styleText('underline', subjectEntry.id),\n ]\n .filter(Boolean)\n .join(' '),\n indent(\n prettyFormat({\n indentSize: indentSize,\n migration,\n subject: subjectEntry.mutations,\n }),\n ),\n ].join('\\n\\n')\n }\n return prettyFormatMutation({\n indentSize,\n migration,\n subject: subjectEntry,\n })\n })\n .join('\\n\\n')\n}\n\nfunction encodeItemRef(ref: KeyedSegment | number): ItemRef {\n return typeof ref === 'number' ? ref : ref._key\n}\n\nfunction badgeStyle(variant: Variant, label: string) {\n const styles: Record<Variant, string> = {\n destructive: styleText(['bgRed', 'black', 'bold'], label),\n incremental: styleText(['bgGreen', 'black', 'bold'], label),\n info: styleText(['bgWhite', 'black'], label),\n maybeDestructive: styleText(['bgYellow', 'black', 'bold'], label),\n }\n\n return styles[variant]\n}\n\nfunction badge(label: string, variant: Variant): string {\n if (!isTty) {\n return `[${label}]`\n }\n\n return badgeStyle(variant, ` ${label} `)\n}\n\nconst mutationImpact: Record<Mutation['type'], Impact> = {\n create: 'incremental',\n createIfNotExists: 'incremental',\n createOrReplace: 'maybeDestructive',\n delete: 'destructive',\n patch: 'maybeDestructive',\n}\n\nfunction documentId(mutation: Mutation): string | undefined {\n if ('id' in mutation) {\n return mutation.id\n }\n\n if ('document' in mutation) {\n return mutation.document._id\n }\n\n return undefined\n}\n\nconst listFormatter = new Intl.ListFormat('en-US', {\n type: 'disjunction',\n})\n\nfunction mutationHeader(mutation: Mutation, migration: Migration): string {\n const mutationType = badge(mutation.type, mutationImpact[mutation.type])\n\n const documentType =\n 'document' in mutation || migration.documentTypes\n ? badge(\n 'document' in mutation\n ? mutation.document._type\n : listFormatter.format(migration.documentTypes ?? []),\n 'info',\n )\n : null\n\n // TODO: Should we list documentType when a mutation can be yielded for any document type?\n return [mutationType, documentType, styleText('underline', documentId(mutation) ?? '')]\n .filter(Boolean)\n .join(' ')\n}\n\nfunction prettyFormatMutation({\n indentSize = 0,\n migration,\n subject,\n}: FormatterOptions<Mutation>): string {\n const lock =\n 'options' in subject ? styleText('cyan', `(if revision==${subject.options?.ifRevision})`) : ''\n const header = [mutationHeader(subject, migration), lock].join(' ')\n const padding = ' '.repeat(indentSize)\n\n if (\n subject.type === 'create' ||\n subject.type === 'createIfNotExists' ||\n subject.type === 'createOrReplace'\n ) {\n return [header, '\\n', indent(JSON.stringify(subject.document, null, 2), indentSize)].join('')\n }\n\n if (subject.type === 'patch') {\n const tree = convertToTree<NodePatch>(subject.patches.flat())\n const paddingLength = Math.max(maxKeyLength(tree.children) + 2, 30)\n\n return [\n header,\n '\\n',\n formatTree<NodePatch>({\n getMessage: (patch: NodePatch) => formatPatchMutation(patch),\n indent: padding,\n node: tree.children,\n paddingLength,\n }),\n ].join('')\n }\n\n return header\n}\n\nfunction formatPatchMutation(patch: NodePatch): string {\n const {op} = patch\n const formattedType = styleText('bold', op.type)\n if (op.type === 'unset') {\n return `${styleText('red', formattedType)}()`\n }\n if (op.type === 'diffMatchPatch') {\n return `${styleText('yellow', formattedType)}(${op.value})`\n }\n if (op.type === 'inc' || op.type === 'dec') {\n return `${styleText('yellow', formattedType)}(${op.amount})`\n }\n if (op.type === 'set') {\n return `${styleText('yellow', formattedType)}(${JSON.stringify(op.value)})`\n }\n if (op.type === 'setIfMissing') {\n return `${styleText('green', formattedType)}(${JSON.stringify(op.value)})`\n }\n if (op.type === 'insert') {\n return `${styleText('green', formattedType)}(${op.position}, ${encodeItemRef(\n op.referenceItem,\n )}, ${JSON.stringify(op.items)})`\n }\n if (op.type === 'replace') {\n return `${styleText('yellow', formattedType)}(${encodeItemRef(op.referenceItem)}, ${JSON.stringify(\n op.items,\n )})`\n }\n if (op.type === 'truncate') {\n return `${styleText('red', formattedType)}(${op.startIndex}, ${op.endIndex})`\n }\n\n throw new Error(`Invalid operation type: ${(op as {type: string}).type}`)\n}\n\nfunction indent(subject: string, size = 2): string {\n const padding = ' '.repeat(size)\n\n return subject\n .split('\\n')\n .map((line) => padding + line)\n .join('\\n')\n}\n"],"names":["isatty","styleText","convertToTree","formatTree","maxKeyLength","isTty","prettyFormat","indentSize","migration","subject","Array","isArray","map","subjectEntry","type","badge","id","undefined","filter","Boolean","join","indent","mutations","prettyFormatMutation","encodeItemRef","ref","_key","badgeStyle","variant","label","styles","destructive","incremental","info","maybeDestructive","mutationImpact","create","createIfNotExists","createOrReplace","delete","patch","documentId","mutation","document","_id","listFormatter","Intl","ListFormat","mutationHeader","mutationType","documentType","documentTypes","_type","format","lock","options","ifRevision","header","padding","repeat","JSON","stringify","tree","patches","flat","paddingLength","Math","max","children","getMessage","formatPatchMutation","node","op","formattedType","value","amount","position","referenceItem","items","startIndex","endIndex","Error","size","split","line"],"mappings":"AAAA,SAAQA,MAAM,QAAO,WAAU;AAC/B,SAAQC,SAAS,QAAO,YAAW;AAKnC,SAAQC,aAAa,EAAEC,UAAU,EAAEC,YAAY,QAAO,YAAW;AAMjE,MAAMC,QAAQL,OAAO;AASrB,OAAO,SAASM,aAAa,EAC3BC,aAAa,CAAC,EACdC,SAAS,EACTC,OAAO,EAC+D;IACtE,OAAO,AAACC,CAAAA,MAAMC,OAAO,CAACF,WAAWA,UAAU;QAACA;KAAQ,AAAD,EAChDG,GAAG,CAAC,CAACC;QACJ,IAAIA,aAAaC,IAAI,KAAK,eAAe;YACvC,OAAO;gBACL;oBACEC,MAAM,eAAe;oBACrBF,aAAaG,EAAE,KAAKC,YAAY,OAAOhB,UAAU,aAAaY,aAAaG,EAAE;iBAC9E,CACEE,MAAM,CAACC,SACPC,IAAI,CAAC;gBACRC,OACEf,aAAa;oBACXC,YAAYA;oBACZC;oBACAC,SAASI,aAAaS,SAAS;gBACjC;aAEH,CAACF,IAAI,CAAC;QACT;QACA,OAAOG,qBAAqB;YAC1BhB;YACAC;YACAC,SAASI;QACX;IACF,GACCO,IAAI,CAAC;AACV;AAEA,SAASI,cAAcC,GAA0B;IAC/C,OAAO,OAAOA,QAAQ,WAAWA,MAAMA,IAAIC,IAAI;AACjD;AAEA,SAASC,WAAWC,OAAgB,EAAEC,KAAa;IACjD,MAAMC,SAAkC;QACtCC,aAAa9B,UAAU;YAAC;YAAS;YAAS;SAAO,EAAE4B;QACnDG,aAAa/B,UAAU;YAAC;YAAW;YAAS;SAAO,EAAE4B;QACrDI,MAAMhC,UAAU;YAAC;YAAW;SAAQ,EAAE4B;QACtCK,kBAAkBjC,UAAU;YAAC;YAAY;YAAS;SAAO,EAAE4B;IAC7D;IAEA,OAAOC,MAAM,CAACF,QAAQ;AACxB;AAEA,SAASb,MAAMc,KAAa,EAAED,OAAgB;IAC5C,IAAI,CAACvB,OAAO;QACV,OAAO,CAAC,CAAC,EAAEwB,MAAM,CAAC,CAAC;IACrB;IAEA,OAAOF,WAAWC,SAAS,CAAC,CAAC,EAAEC,MAAM,CAAC,CAAC;AACzC;AAEA,MAAMM,iBAAmD;IACvDC,QAAQ;IACRC,mBAAmB;IACnBC,iBAAiB;IACjBC,QAAQ;IACRC,OAAO;AACT;AAEA,SAASC,WAAWC,QAAkB;IACpC,IAAI,QAAQA,UAAU;QACpB,OAAOA,SAAS1B,EAAE;IACpB;IAEA,IAAI,cAAc0B,UAAU;QAC1B,OAAOA,SAASC,QAAQ,CAACC,GAAG;IAC9B;IAEA,OAAO3B;AACT;AAEA,MAAM4B,gBAAgB,IAAIC,KAAKC,UAAU,CAAC,SAAS;IACjDjC,MAAM;AACR;AAEA,SAASkC,eAAeN,QAAkB,EAAElC,SAAoB;IAC9D,MAAMyC,eAAelC,MAAM2B,SAAS5B,IAAI,EAAEqB,cAAc,CAACO,SAAS5B,IAAI,CAAC;IAEvE,MAAMoC,eACJ,cAAcR,YAAYlC,UAAU2C,aAAa,GAC7CpC,MACE,cAAc2B,WACVA,SAASC,QAAQ,CAACS,KAAK,GACvBP,cAAcQ,MAAM,CAAC7C,UAAU2C,aAAa,IAAI,EAAE,GACtD,UAEF;IAEN,0FAA0F;IAC1F,OAAO;QAACF;QAAcC;QAAcjD,UAAU,aAAawC,WAAWC,aAAa;KAAI,CACpFxB,MAAM,CAACC,SACPC,IAAI,CAAC;AACV;AAEA,SAASG,qBAAqB,EAC5BhB,aAAa,CAAC,EACdC,SAAS,EACTC,OAAO,EACoB;IAC3B,MAAM6C,OACJ,aAAa7C,UAAUR,UAAU,QAAQ,CAAC,cAAc,EAAEQ,QAAQ8C,OAAO,EAAEC,WAAW,CAAC,CAAC,IAAI;IAC9F,MAAMC,SAAS;QAACT,eAAevC,SAASD;QAAY8C;KAAK,CAAClC,IAAI,CAAC;IAC/D,MAAMsC,UAAU,IAAIC,MAAM,CAACpD;IAE3B,IACEE,QAAQK,IAAI,KAAK,YACjBL,QAAQK,IAAI,KAAK,uBACjBL,QAAQK,IAAI,KAAK,mBACjB;QACA,OAAO;YAAC2C;YAAQ;YAAMpC,OAAOuC,KAAKC,SAAS,CAACpD,QAAQkC,QAAQ,EAAE,MAAM,IAAIpC;SAAY,CAACa,IAAI,CAAC;IAC5F;IAEA,IAAIX,QAAQK,IAAI,KAAK,SAAS;QAC5B,MAAMgD,OAAO5D,cAAyBO,QAAQsD,OAAO,CAACC,IAAI;QAC1D,MAAMC,gBAAgBC,KAAKC,GAAG,CAAC/D,aAAa0D,KAAKM,QAAQ,IAAI,GAAG;QAEhE,OAAO;YACLX;YACA;YACAtD,WAAsB;gBACpBkE,YAAY,CAAC7B,QAAqB8B,oBAAoB9B;gBACtDnB,QAAQqC;gBACRa,MAAMT,KAAKM,QAAQ;gBACnBH;YACF;SACD,CAAC7C,IAAI,CAAC;IACT;IAEA,OAAOqC;AACT;AAEA,SAASa,oBAAoB9B,KAAgB;IAC3C,MAAM,EAACgC,EAAE,EAAC,GAAGhC;IACb,MAAMiC,gBAAgBxE,UAAU,QAAQuE,GAAG1D,IAAI;IAC/C,IAAI0D,GAAG1D,IAAI,KAAK,SAAS;QACvB,OAAO,GAAGb,UAAU,OAAOwE,eAAe,EAAE,CAAC;IAC/C;IACA,IAAID,GAAG1D,IAAI,KAAK,kBAAkB;QAChC,OAAO,GAAGb,UAAU,UAAUwE,eAAe,CAAC,EAAED,GAAGE,KAAK,CAAC,CAAC,CAAC;IAC7D;IACA,IAAIF,GAAG1D,IAAI,KAAK,SAAS0D,GAAG1D,IAAI,KAAK,OAAO;QAC1C,OAAO,GAAGb,UAAU,UAAUwE,eAAe,CAAC,EAAED,GAAGG,MAAM,CAAC,CAAC,CAAC;IAC9D;IACA,IAAIH,GAAG1D,IAAI,KAAK,OAAO;QACrB,OAAO,GAAGb,UAAU,UAAUwE,eAAe,CAAC,EAAEb,KAAKC,SAAS,CAACW,GAAGE,KAAK,EAAE,CAAC,CAAC;IAC7E;IACA,IAAIF,GAAG1D,IAAI,KAAK,gBAAgB;QAC9B,OAAO,GAAGb,UAAU,SAASwE,eAAe,CAAC,EAAEb,KAAKC,SAAS,CAACW,GAAGE,KAAK,EAAE,CAAC,CAAC;IAC5E;IACA,IAAIF,GAAG1D,IAAI,KAAK,UAAU;QACxB,OAAO,GAAGb,UAAU,SAASwE,eAAe,CAAC,EAAED,GAAGI,QAAQ,CAAC,EAAE,EAAEpD,cAC7DgD,GAAGK,aAAa,EAChB,EAAE,EAAEjB,KAAKC,SAAS,CAACW,GAAGM,KAAK,EAAE,CAAC,CAAC;IACnC;IACA,IAAIN,GAAG1D,IAAI,KAAK,WAAW;QACzB,OAAO,GAAGb,UAAU,UAAUwE,eAAe,CAAC,EAAEjD,cAAcgD,GAAGK,aAAa,EAAE,EAAE,EAAEjB,KAAKC,SAAS,CAChGW,GAAGM,KAAK,EACR,CAAC,CAAC;IACN;IACA,IAAIN,GAAG1D,IAAI,KAAK,YAAY;QAC1B,OAAO,GAAGb,UAAU,OAAOwE,eAAe,CAAC,EAAED,GAAGO,UAAU,CAAC,EAAE,EAAEP,GAAGQ,QAAQ,CAAC,CAAC,CAAC;IAC/E;IAEA,MAAM,IAAIC,MAAM,CAAC,wBAAwB,EAAE,AAACT,GAAsB1D,IAAI,EAAE;AAC1E;AAEA,SAASO,OAAOZ,OAAe,EAAEyE,OAAO,CAAC;IACvC,MAAMxB,UAAU,IAAIC,MAAM,CAACuB;IAE3B,OAAOzE,QACJ0E,KAAK,CAAC,MACNvE,GAAG,CAAC,CAACwE,OAAS1B,UAAU0B,MACxBhE,IAAI,CAAC;AACV"}
@@ -0,0 +1,75 @@
1
+ import path from 'node:path';
2
+ import { importModule, subdebug } from '@sanity/cli-core';
3
+ import { MIGRATION_SCRIPT_EXTENSIONS, MIGRATIONS_DIRECTORY } from './constants.js';
4
+ import { fileExists } from './fileExists.js';
5
+ const debug = subdebug('migration:resolveMigrationScript');
6
+ /**
7
+ * Resolves the potential paths to a migration script.
8
+ * Considers the following paths (where `<ext>` is 'mjs', 'js', 'ts' or 'cjs'):
9
+ *
10
+ * - `<migrationsDir>/<migrationName>.<ext>`
11
+ * - `<migrationsDir>/<migrationName>/index.<ext>`
12
+ *
13
+ * Note that all possible paths are returned, even if the files do not exist.
14
+ * Check the `mod` property to see if a module could actually be loaded.
15
+ *
16
+ * @param workDir - Working directory of the studio
17
+ * @param migrationName - The name of the migration directory to resolve
18
+ * @returns An array of potential migration scripts
19
+ * @internal
20
+ */ export async function resolveMigrationScript(workDir, migrationName) {
21
+ const locations = [
22
+ migrationName,
23
+ path.join(migrationName, 'index')
24
+ ];
25
+ const results = [];
26
+ for (const location of locations){
27
+ for (const ext of MIGRATION_SCRIPT_EXTENSIONS){
28
+ const relativePath = path.join(MIGRATIONS_DIRECTORY, `${location}.${ext}`);
29
+ const absolutePath = path.resolve(workDir, relativePath);
30
+ let mod;
31
+ // Check if the file exists before trying to import it
32
+ const exists = await fileExists(absolutePath);
33
+ if (!exists) {
34
+ continue;
35
+ }
36
+ try {
37
+ debug(`importing migration from ${absolutePath}`);
38
+ const imported = await importModule(absolutePath, {
39
+ default: false
40
+ });
41
+ // Handle both ESM and CJS default exports
42
+ mod = imported;
43
+ } catch (err) {
44
+ debug(`error importing migration from ${absolutePath}`, err);
45
+ // Ignore MODULE_NOT_FOUND errors, but throw others
46
+ if (err.code !== 'MODULE_NOT_FOUND' && err.code !== 'ERR_MODULE_NOT_FOUND') {
47
+ throw new Error(`Error loading migration: ${err.message}`, {
48
+ cause: err
49
+ });
50
+ }
51
+ }
52
+ results.push({
53
+ absolutePath,
54
+ mod,
55
+ relativePath
56
+ });
57
+ }
58
+ }
59
+ return results;
60
+ }
61
+ /**
62
+ * Checks whether or not the passed resolved migration script is actually loadable (eg has a default export)
63
+ *
64
+ * @param script - The resolved migration script to check
65
+ * @returns `true` if the script is loadable, `false` otherwise
66
+ * @internal
67
+ */ export function isLoadableMigrationScript(script) {
68
+ if (script.mod === undefined || typeof script.mod.default !== 'object' || script.mod.default === null || Array.isArray(script.mod.default)) {
69
+ return false;
70
+ }
71
+ const mod = script.mod.default;
72
+ return typeof mod.title === 'string' && mod.migrate !== undefined;
73
+ }
74
+
75
+ //# sourceMappingURL=resolveMigrationScript.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/migration/resolveMigrationScript.ts"],"sourcesContent":["import path from 'node:path'\n\nimport {importModule, subdebug} from '@sanity/cli-core'\nimport {type Migration} from '@sanity/migrate'\n\nimport {MIGRATION_SCRIPT_EXTENSIONS, MIGRATIONS_DIRECTORY} from './constants.js'\nimport {fileExists} from './fileExists.js'\n\ninterface ResolvedMigrationScript {\n /**\n * Absolute path to the migration script\n */\n absolutePath: string\n /**\n * Relative path from the working directory to the migration script\n */\n relativePath: string\n\n /**\n * The migration module, if it could be resolved - otherwise `undefined`\n */\n mod?: {default: Migration; down?: unknown; up?: unknown}\n}\n\nconst debug = subdebug('migration:resolveMigrationScript')\n\n/**\n * Resolves the potential paths to a migration script.\n * Considers the following paths (where `<ext>` is 'mjs', 'js', 'ts' or 'cjs'):\n *\n * - `<migrationsDir>/<migrationName>.<ext>`\n * - `<migrationsDir>/<migrationName>/index.<ext>`\n *\n * Note that all possible paths are returned, even if the files do not exist.\n * Check the `mod` property to see if a module could actually be loaded.\n *\n * @param workDir - Working directory of the studio\n * @param migrationName - The name of the migration directory to resolve\n * @returns An array of potential migration scripts\n * @internal\n */\nexport async function resolveMigrationScript(\n workDir: string,\n migrationName: string,\n): Promise<ResolvedMigrationScript[]> {\n const locations = [migrationName, path.join(migrationName, 'index')]\n const results: ResolvedMigrationScript[] = []\n\n for (const location of locations) {\n for (const ext of MIGRATION_SCRIPT_EXTENSIONS) {\n const relativePath = path.join(MIGRATIONS_DIRECTORY, `${location}.${ext}`)\n const absolutePath = path.resolve(workDir, relativePath)\n let mod: {default: Migration; down?: unknown; up?: unknown} | undefined\n\n // Check if the file exists before trying to import it\n const exists = await fileExists(absolutePath)\n if (!exists) {\n continue\n }\n\n try {\n debug(`importing migration from ${absolutePath}`)\n const imported = await importModule<{default: Migration; down?: unknown; up?: unknown}>(\n absolutePath,\n {\n default: false,\n },\n )\n // Handle both ESM and CJS default exports\n mod = imported\n } catch (err) {\n debug(`error importing migration from ${absolutePath}`, err)\n // Ignore MODULE_NOT_FOUND errors, but throw others\n if (\n (err as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND' &&\n (err as NodeJS.ErrnoException).code !== 'ERR_MODULE_NOT_FOUND'\n ) {\n throw new Error(`Error loading migration: ${(err as Error).message}`, {cause: err})\n }\n }\n\n results.push({absolutePath, mod, relativePath})\n }\n }\n\n return results\n}\n\n/**\n * Checks whether or not the passed resolved migration script is actually loadable (eg has a default export)\n *\n * @param script - The resolved migration script to check\n * @returns `true` if the script is loadable, `false` otherwise\n * @internal\n */\nexport function isLoadableMigrationScript(\n script: ResolvedMigrationScript,\n): script is Required<ResolvedMigrationScript> {\n if (\n script.mod === undefined ||\n typeof script.mod.default !== 'object' ||\n script.mod.default === null ||\n Array.isArray(script.mod.default)\n ) {\n return false\n }\n\n const mod = script.mod.default\n return typeof mod.title === 'string' && mod.migrate !== undefined\n}\n"],"names":["path","importModule","subdebug","MIGRATION_SCRIPT_EXTENSIONS","MIGRATIONS_DIRECTORY","fileExists","debug","resolveMigrationScript","workDir","migrationName","locations","join","results","location","ext","relativePath","absolutePath","resolve","mod","exists","imported","default","err","code","Error","message","cause","push","isLoadableMigrationScript","script","undefined","Array","isArray","title","migrate"],"mappings":"AAAA,OAAOA,UAAU,YAAW;AAE5B,SAAQC,YAAY,EAAEC,QAAQ,QAAO,mBAAkB;AAGvD,SAAQC,2BAA2B,EAAEC,oBAAoB,QAAO,iBAAgB;AAChF,SAAQC,UAAU,QAAO,kBAAiB;AAkB1C,MAAMC,QAAQJ,SAAS;AAEvB;;;;;;;;;;;;;;CAcC,GACD,OAAO,eAAeK,uBACpBC,OAAe,EACfC,aAAqB;IAErB,MAAMC,YAAY;QAACD;QAAeT,KAAKW,IAAI,CAACF,eAAe;KAAS;IACpE,MAAMG,UAAqC,EAAE;IAE7C,KAAK,MAAMC,YAAYH,UAAW;QAChC,KAAK,MAAMI,OAAOX,4BAA6B;YAC7C,MAAMY,eAAef,KAAKW,IAAI,CAACP,sBAAsB,GAAGS,SAAS,CAAC,EAAEC,KAAK;YACzE,MAAME,eAAehB,KAAKiB,OAAO,CAACT,SAASO;YAC3C,IAAIG;YAEJ,sDAAsD;YACtD,MAAMC,SAAS,MAAMd,WAAWW;YAChC,IAAI,CAACG,QAAQ;gBACX;YACF;YAEA,IAAI;gBACFb,MAAM,CAAC,yBAAyB,EAAEU,cAAc;gBAChD,MAAMI,WAAW,MAAMnB,aACrBe,cACA;oBACEK,SAAS;gBACX;gBAEF,0CAA0C;gBAC1CH,MAAME;YACR,EAAE,OAAOE,KAAK;gBACZhB,MAAM,CAAC,+BAA+B,EAAEU,cAAc,EAAEM;gBACxD,mDAAmD;gBACnD,IACE,AAACA,IAA8BC,IAAI,KAAK,sBACxC,AAACD,IAA8BC,IAAI,KAAK,wBACxC;oBACA,MAAM,IAAIC,MAAM,CAAC,yBAAyB,EAAE,AAACF,IAAcG,OAAO,EAAE,EAAE;wBAACC,OAAOJ;oBAAG;gBACnF;YACF;YAEAV,QAAQe,IAAI,CAAC;gBAACX;gBAAcE;gBAAKH;YAAY;QAC/C;IACF;IAEA,OAAOH;AACT;AAEA;;;;;;CAMC,GACD,OAAO,SAASgB,0BACdC,MAA+B;IAE/B,IACEA,OAAOX,GAAG,KAAKY,aACf,OAAOD,OAAOX,GAAG,CAACG,OAAO,KAAK,YAC9BQ,OAAOX,GAAG,CAACG,OAAO,KAAK,QACvBU,MAAMC,OAAO,CAACH,OAAOX,GAAG,CAACG,OAAO,GAChC;QACA,OAAO;IACT;IAEA,MAAMH,MAAMW,OAAOX,GAAG,CAACG,OAAO;IAC9B,OAAO,OAAOH,IAAIe,KAAK,KAAK,YAAYf,IAAIgB,OAAO,KAAKJ;AAC1D"}
@@ -0,0 +1,50 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { MIGRATION_SCRIPT_EXTENSIONS, MIGRATIONS_DIRECTORY } from './constants.js';
4
+ import { isLoadableMigrationScript, resolveMigrationScript } from './resolveMigrationScript.js';
5
+ /**
6
+ * Removes migration script extensions from a filename
7
+ *
8
+ * @param fileName - The filename to process
9
+ * @returns The filename without the extension
10
+ * @internal
11
+ */ function removeMigrationScriptExtension(fileName) {
12
+ // Remove `.ts`, `.js` etc from the end of a filename
13
+ const ext = MIGRATION_SCRIPT_EXTENSIONS.find((e)=>fileName.endsWith(`.${e}`));
14
+ return ext ? path.basename(fileName, `.${ext}`) : fileName;
15
+ }
16
+ /**
17
+ * Resolves all migrations in the studio working directory
18
+ *
19
+ * @param workDir - The studio working directory
20
+ * @returns Array of migrations and their respective paths
21
+ * @internal
22
+ */ export async function resolveMigrations(workDir) {
23
+ const migrationsDir = path.join(workDir, MIGRATIONS_DIRECTORY);
24
+ const migrationEntries = await readdir(migrationsDir, {
25
+ withFileTypes: true
26
+ });
27
+ const migrations = [];
28
+ const seen = new Set();
29
+ for (const entry of migrationEntries){
30
+ const entryName = entry.isDirectory() ? entry.name : removeMigrationScriptExtension(entry.name);
31
+ // A file (e.g. `foo.ts`) and a directory (e.g. `foo/`) can both map to the
32
+ // same id; only resolve each id once.
33
+ if (seen.has(entryName)) {
34
+ continue;
35
+ }
36
+ // `resolveMigrationScript` may return several loadable candidates for a
37
+ // single id (e.g. both `foo.ts` and `foo/index.ts`). List it just once.
38
+ const candidate = (await resolveMigrationScript(workDir, entryName)).find((script)=>isLoadableMigrationScript(script));
39
+ if (candidate) {
40
+ seen.add(entryName);
41
+ migrations.push({
42
+ id: entryName,
43
+ migration: candidate.mod.default
44
+ });
45
+ }
46
+ }
47
+ return migrations;
48
+ }
49
+
50
+ //# sourceMappingURL=resolveMigrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/migration/resolveMigrations.ts"],"sourcesContent":["import {readdir} from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {type Migration} from '@sanity/migrate'\n\nimport {MIGRATION_SCRIPT_EXTENSIONS, MIGRATIONS_DIRECTORY} from './constants.js'\nimport {isLoadableMigrationScript, resolveMigrationScript} from './resolveMigrationScript.js'\n\n/**\n * A resolved migration, where you are guaranteed that the migration file exists\n *\n * @internal\n */\ninterface ResolvedMigration {\n id: string\n migration: Migration\n}\n\n/**\n * Removes migration script extensions from a filename\n *\n * @param fileName - The filename to process\n * @returns The filename without the extension\n * @internal\n */\nfunction removeMigrationScriptExtension(fileName: string): string {\n // Remove `.ts`, `.js` etc from the end of a filename\n const ext = MIGRATION_SCRIPT_EXTENSIONS.find((e) => fileName.endsWith(`.${e}`))\n return ext ? path.basename(fileName, `.${ext}`) : fileName\n}\n\n/**\n * Resolves all migrations in the studio working directory\n *\n * @param workDir - The studio working directory\n * @returns Array of migrations and their respective paths\n * @internal\n */\nexport async function resolveMigrations(workDir: string): Promise<ResolvedMigration[]> {\n const migrationsDir = path.join(workDir, MIGRATIONS_DIRECTORY)\n const migrationEntries = await readdir(migrationsDir, {withFileTypes: true})\n\n const migrations: ResolvedMigration[] = []\n const seen = new Set<string>()\n for (const entry of migrationEntries) {\n const entryName = entry.isDirectory() ? entry.name : removeMigrationScriptExtension(entry.name)\n // A file (e.g. `foo.ts`) and a directory (e.g. `foo/`) can both map to the\n // same id; only resolve each id once.\n if (seen.has(entryName)) {\n continue\n }\n\n // `resolveMigrationScript` may return several loadable candidates for a\n // single id (e.g. both `foo.ts` and `foo/index.ts`). List it just once.\n const candidate = (await resolveMigrationScript(workDir, entryName)).find((script) =>\n isLoadableMigrationScript(script),\n )\n if (candidate) {\n seen.add(entryName)\n migrations.push({id: entryName, migration: candidate.mod.default})\n }\n }\n\n return migrations\n}\n"],"names":["readdir","path","MIGRATION_SCRIPT_EXTENSIONS","MIGRATIONS_DIRECTORY","isLoadableMigrationScript","resolveMigrationScript","removeMigrationScriptExtension","fileName","ext","find","e","endsWith","basename","resolveMigrations","workDir","migrationsDir","join","migrationEntries","withFileTypes","migrations","seen","Set","entry","entryName","isDirectory","name","has","candidate","script","add","push","id","migration","mod","default"],"mappings":"AAAA,SAAQA,OAAO,QAAO,mBAAkB;AACxC,OAAOC,UAAU,YAAW;AAI5B,SAAQC,2BAA2B,EAAEC,oBAAoB,QAAO,iBAAgB;AAChF,SAAQC,yBAAyB,EAAEC,sBAAsB,QAAO,8BAA6B;AAY7F;;;;;;CAMC,GACD,SAASC,+BAA+BC,QAAgB;IACtD,qDAAqD;IACrD,MAAMC,MAAMN,4BAA4BO,IAAI,CAAC,CAACC,IAAMH,SAASI,QAAQ,CAAC,CAAC,CAAC,EAAED,GAAG;IAC7E,OAAOF,MAAMP,KAAKW,QAAQ,CAACL,UAAU,CAAC,CAAC,EAAEC,KAAK,IAAID;AACpD;AAEA;;;;;;CAMC,GACD,OAAO,eAAeM,kBAAkBC,OAAe;IACrD,MAAMC,gBAAgBd,KAAKe,IAAI,CAACF,SAASX;IACzC,MAAMc,mBAAmB,MAAMjB,QAAQe,eAAe;QAACG,eAAe;IAAI;IAE1E,MAAMC,aAAkC,EAAE;IAC1C,MAAMC,OAAO,IAAIC;IACjB,KAAK,MAAMC,SAASL,iBAAkB;QACpC,MAAMM,YAAYD,MAAME,WAAW,KAAKF,MAAMG,IAAI,GAAGnB,+BAA+BgB,MAAMG,IAAI;QAC9F,2EAA2E;QAC3E,sCAAsC;QACtC,IAAIL,KAAKM,GAAG,CAACH,YAAY;YACvB;QACF;QAEA,wEAAwE;QACxE,wEAAwE;QACxE,MAAMI,YAAY,AAAC,CAAA,MAAMtB,uBAAuBS,SAASS,UAAS,EAAGd,IAAI,CAAC,CAACmB,SACzExB,0BAA0BwB;QAE5B,IAAID,WAAW;YACbP,KAAKS,GAAG,CAACN;YACTJ,WAAWW,IAAI,CAAC;gBAACC,IAAIR;gBAAWS,WAAWL,UAAUM,GAAG,CAACC,OAAO;YAAA;QAClE;IACF;IAEA,OAAOf;AACT"}
@@ -0,0 +1,7 @@
1
+ export { minimalAdvanced } from './minimalAdvanced.js';
2
+ export { minimalSimple } from './minimalSimple.js';
3
+ export { renameField } from './renameField.js';
4
+ export { renameType } from './renameType.js';
5
+ export { stringToPTE } from './stringToPTE.js';
6
+
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/index.ts"],"sourcesContent":["export {minimalAdvanced} from './minimalAdvanced.js'\nexport {minimalSimple} from './minimalSimple.js'\nexport {renameField} from './renameField.js'\nexport {renameType} from './renameType.js'\nexport {stringToPTE} from './stringToPTE.js'\n"],"names":["minimalAdvanced","minimalSimple","renameField","renameType","stringToPTE"],"mappings":"AAAA,SAAQA,eAAe,QAAO,uBAAsB;AACpD,SAAQC,aAAa,QAAO,qBAAoB;AAChD,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAAQC,UAAU,QAAO,kBAAiB;AAC1C,SAAQC,WAAW,QAAO,mBAAkB"}
@@ -0,0 +1,21 @@
1
+ export const minimalAdvanced = ({ documentTypes, migrationName })=>`import {defineMigration, patch, at, setIfMissing} from 'sanity/migrate'
2
+
3
+ /**
4
+ * this migration will set \`Default title\` on all documents that are missing a title
5
+ * and make \`true\` the default value for the \`enabled\` field
6
+ */
7
+ export default defineMigration({
8
+ title: ${JSON.stringify(migrationName)},
9
+ ${documentTypes.length > 0 ? ` documentTypes: [${documentTypes.map((t)=>JSON.stringify(t)).join(', ')}],\n` : ''}
10
+ async *migrate(documents, context) {
11
+ for await (const document of documents()) {
12
+ yield patch(document._id, [
13
+ at('title', setIfMissing('Default title')),
14
+ at('enabled', setIfMissing(true)),
15
+ ])
16
+ }
17
+ }
18
+ })
19
+ `;
20
+
21
+ //# sourceMappingURL=minimalAdvanced.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/minimalAdvanced.ts"],"sourcesContent":["export const minimalAdvanced = ({\n documentTypes,\n migrationName,\n}: {\n documentTypes: string[]\n migrationName: string\n}) => `import {defineMigration, patch, at, setIfMissing} from 'sanity/migrate'\n\n/**\n * this migration will set \\`Default title\\` on all documents that are missing a title\n * and make \\`true\\` the default value for the \\`enabled\\` field\n */\nexport default defineMigration({\n title: ${JSON.stringify(migrationName)},\n${\n documentTypes.length > 0\n ? ` documentTypes: [${documentTypes.map((t) => JSON.stringify(t)).join(', ')}],\\n`\n : ''\n}\n async *migrate(documents, context) {\n for await (const document of documents()) {\n yield patch(document._id, [\n at('title', setIfMissing('Default title')),\n at('enabled', setIfMissing(true)),\n ])\n }\n }\n})\n`\n"],"names":["minimalAdvanced","documentTypes","migrationName","JSON","stringify","length","map","t","join"],"mappings":"AAAA,OAAO,MAAMA,kBAAkB,CAAC,EAC9BC,aAAa,EACbC,aAAa,EAId,GAAK,CAAC;;;;;;;SAOE,EAAEC,KAAKC,SAAS,CAACF,eAAe;AACzC,EACED,cAAcI,MAAM,GAAG,IACnB,CAAC,kBAAkB,EAAEJ,cAAcK,GAAG,CAAC,CAACC,IAAMJ,KAAKC,SAAS,CAACG,IAAIC,IAAI,CAAC,MAAM,IAAI,CAAC,GACjF,GACL;;;;;;;;;;AAUD,CAAC,CAAA"}
@@ -0,0 +1,61 @@
1
+ export const minimalSimple = ({ documentTypes, migrationName })=>`import {at, defineMigration, setIfMissing, unset} from 'sanity/migrate'
2
+
3
+ export default defineMigration({
4
+ title: ${JSON.stringify(migrationName)},
5
+ ${documentTypes.length > 0 ? ` documentTypes: [${documentTypes.map((t)=>JSON.stringify(t)).join(', ')}],\n` : ''}
6
+ migrate: {
7
+ document(doc, context) {
8
+ // this will be called for every document of the matching type
9
+ // any patch returned will be applied to the document
10
+ // you can also return mutations that touches other documents
11
+
12
+ return at('title', setIfMissing('Default title'))
13
+ },
14
+ node(node, path, context) {
15
+ // this will be called for every node in every document of the matching type
16
+ // any patch returned will be applied to the document
17
+ // you can also return mutations that touches other documents
18
+
19
+ if (typeof node === 'string' && node === 'deleteme') {
20
+ return unset()
21
+ }
22
+ },
23
+ object(node, path, context) {
24
+ // this will be called for every object node in every document of the matching type
25
+ // any patch returned will be applied to the document
26
+ // you can also return mutations that touches other documents
27
+ if (node._type === 'author') {
28
+ // make sure all authors objects have a books array
29
+ return at('books', setIfMissing([]))
30
+ }
31
+ },
32
+ array(node, path, context) {
33
+ // this will be called for every array node in every document of the matching type
34
+ // any patch returned will be applied to the document
35
+ // you can also return mutations that touches other documents
36
+ },
37
+ string(node, path, context) {
38
+ // this will be called for every string node in every document of the matching type
39
+ // any patch returned will be applied to the document
40
+ // you can also return mutations that touches other documents
41
+ },
42
+ number(node, path, context) {
43
+ // this will be called for every number node in every document of the matching type
44
+ // any patch returned will be applied to the document
45
+ // you can also return mutations that touches other documents
46
+ },
47
+ boolean(node, path, context) {
48
+ // this will be called for every boolean node in every document of the matching type
49
+ // any patch returned will be applied to the document
50
+ // you can also return mutations that touches other documents
51
+ },
52
+ null(node, path, context) {
53
+ // this will be called for every null node in every document of the matching type
54
+ // any patch returned will be applied to the document
55
+ // you can also return mutations that touches other documents
56
+ },
57
+ },
58
+ })
59
+ `;
60
+
61
+ //# sourceMappingURL=minimalSimple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/minimalSimple.ts"],"sourcesContent":["export const minimalSimple = ({\n documentTypes,\n migrationName,\n}: {\n documentTypes: string[]\n migrationName: string\n}) => `import {at, defineMigration, setIfMissing, unset} from 'sanity/migrate'\n\nexport default defineMigration({\n title: ${JSON.stringify(migrationName)},\n${\n documentTypes.length > 0\n ? ` documentTypes: [${documentTypes.map((t) => JSON.stringify(t)).join(', ')}],\\n`\n : ''\n}\n migrate: {\n document(doc, context) {\n // this will be called for every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n\n return at('title', setIfMissing('Default title'))\n },\n node(node, path, context) {\n // this will be called for every node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n\n if (typeof node === 'string' && node === 'deleteme') {\n return unset()\n }\n },\n object(node, path, context) {\n // this will be called for every object node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n if (node._type === 'author') {\n // make sure all authors objects have a books array\n return at('books', setIfMissing([]))\n }\n },\n array(node, path, context) {\n // this will be called for every array node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n },\n string(node, path, context) {\n // this will be called for every string node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n },\n number(node, path, context) {\n // this will be called for every number node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n },\n boolean(node, path, context) {\n // this will be called for every boolean node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n },\n null(node, path, context) {\n // this will be called for every null node in every document of the matching type\n // any patch returned will be applied to the document\n // you can also return mutations that touches other documents\n },\n },\n})\n`\n"],"names":["minimalSimple","documentTypes","migrationName","JSON","stringify","length","map","t","join"],"mappings":"AAAA,OAAO,MAAMA,gBAAgB,CAAC,EAC5BC,aAAa,EACbC,aAAa,EAId,GAAK,CAAC;;;SAGE,EAAEC,KAAKC,SAAS,CAACF,eAAe;AACzC,EACED,cAAcI,MAAM,GAAG,IACnB,CAAC,kBAAkB,EAAEJ,cAAcK,GAAG,CAAC,CAACC,IAAMJ,KAAKC,SAAS,CAACG,IAAIC,IAAI,CAAC,MAAM,IAAI,CAAC,GACjF,GACL;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDD,CAAC,CAAA"}
@@ -0,0 +1,20 @@
1
+ export const renameField = ({ documentTypes, migrationName })=>`import {defineMigration, at, setIfMissing, unset} from 'sanity/migrate'
2
+
3
+ const from = 'oldFieldName'
4
+ const to = 'newFieldName'
5
+
6
+ export default defineMigration({
7
+ title: ${JSON.stringify(migrationName)},
8
+ ${documentTypes.length > 0 ? ` documentTypes: [${documentTypes.map((t)=>JSON.stringify(t)).join(', ')}],\n` : ''}
9
+ migrate: {
10
+ document(doc, context) {
11
+ return [
12
+ at(to, setIfMissing(doc[from])),
13
+ at(from, unset())
14
+ ]
15
+ }
16
+ }
17
+ })
18
+ `;
19
+
20
+ //# sourceMappingURL=renameField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/renameField.ts"],"sourcesContent":["export const renameField = ({\n documentTypes,\n migrationName,\n}: {\n documentTypes: string[]\n migrationName: string\n}) => `import {defineMigration, at, setIfMissing, unset} from 'sanity/migrate'\n\nconst from = 'oldFieldName'\nconst to = 'newFieldName'\n\nexport default defineMigration({\n title: ${JSON.stringify(migrationName)},\n${\n documentTypes.length > 0\n ? ` documentTypes: [${documentTypes.map((t) => JSON.stringify(t)).join(', ')}],\\n`\n : ''\n}\n migrate: {\n document(doc, context) {\n return [\n at(to, setIfMissing(doc[from])),\n at(from, unset())\n ]\n }\n }\n})\n`\n"],"names":["renameField","documentTypes","migrationName","JSON","stringify","length","map","t","join"],"mappings":"AAAA,OAAO,MAAMA,cAAc,CAAC,EAC1BC,aAAa,EACbC,aAAa,EAId,GAAK,CAAC;;;;;;SAME,EAAEC,KAAKC,SAAS,CAACF,eAAe;AACzC,EACED,cAAcI,MAAM,GAAG,IACnB,CAAC,kBAAkB,EAAEJ,cAAcK,GAAG,CAAC,CAACC,IAAMJ,KAAKC,SAAS,CAACG,IAAIC,IAAI,CAAC,MAAM,IAAI,CAAC,GACjF,GACL;;;;;;;;;;AAUD,CAAC,CAAA"}
@@ -0,0 +1,19 @@
1
+ export const renameType = ({ documentTypes, migrationName })=>`import {defineMigration, at, set} from 'sanity/migrate'
2
+
3
+ const oldType = 'old'
4
+ const newType = 'new'
5
+
6
+ export default defineMigration({
7
+ title: ${JSON.stringify(migrationName)},
8
+ ${documentTypes.length > 0 ? ` documentTypes: [${documentTypes.map((t)=>JSON.stringify(t)).join(', ')}],\n` : ''}
9
+ migrate: {
10
+ object(object, path, context) {
11
+ if (object._type === oldType) {
12
+ return at('_type', set(newType))
13
+ }
14
+ }
15
+ }
16
+ })
17
+ `;
18
+
19
+ //# sourceMappingURL=renameType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/renameType.ts"],"sourcesContent":["export const renameType = ({\n documentTypes,\n migrationName,\n}: {\n documentTypes: string[]\n migrationName: string\n}) => `import {defineMigration, at, set} from 'sanity/migrate'\n\nconst oldType = 'old'\nconst newType = 'new'\n\nexport default defineMigration({\n title: ${JSON.stringify(migrationName)},\n${\n documentTypes.length > 0\n ? ` documentTypes: [${documentTypes.map((t) => JSON.stringify(t)).join(', ')}],\\n`\n : ''\n}\n migrate: {\n object(object, path, context) {\n if (object._type === oldType) {\n return at('_type', set(newType))\n }\n }\n }\n})\n`\n"],"names":["renameType","documentTypes","migrationName","JSON","stringify","length","map","t","join"],"mappings":"AAAA,OAAO,MAAMA,aAAa,CAAC,EACzBC,aAAa,EACbC,aAAa,EAId,GAAK,CAAC;;;;;;SAME,EAAEC,KAAKC,SAAS,CAACF,eAAe;AACzC,EACED,cAAcI,MAAM,GAAG,IACnB,CAAC,kBAAkB,EAAEJ,cAAcK,GAAG,CAAC,CAACC,IAAMJ,KAAKC,SAAS,CAACG,IAAIC,IAAI,CAAC,MAAM,IAAI,CAAC,GACjF,GACL;;;;;;;;;AASD,CAAC,CAAA"}
@@ -0,0 +1,32 @@
1
+ export const stringToPTE = ({ documentTypes, migrationName })=>`import {pathsAreEqual, stringToPath} from 'sanity'
2
+ import {defineMigration, set} from 'sanity/migrate'
3
+
4
+ const targetPath = stringToPath('some.path')
5
+
6
+ export default defineMigration({
7
+ title: ${JSON.stringify(migrationName)},
8
+ ${documentTypes.length > 0 ? ` documentTypes: [${documentTypes.map((t)=>JSON.stringify(t)).join(', ')}],\n` : ''}
9
+ migrate: {
10
+ string(node, path, ctx) {
11
+ if (pathsAreEqual(path, targetPath)) {
12
+ return set([
13
+ {
14
+ style: 'normal',
15
+ _type: 'block',
16
+ children: [
17
+ {
18
+ _type: 'span',
19
+ marks: [],
20
+ text: node,
21
+ },
22
+ ],
23
+ markDefs: [],
24
+ },
25
+ ])
26
+ }
27
+ },
28
+ },
29
+ })
30
+ `;
31
+
32
+ //# sourceMappingURL=stringToPTE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/actions/migration/templates/stringToPTE.ts"],"sourcesContent":["export const stringToPTE = ({\n documentTypes,\n migrationName,\n}: {\n documentTypes: string[]\n migrationName: string\n}) => `import {pathsAreEqual, stringToPath} from 'sanity'\nimport {defineMigration, set} from 'sanity/migrate'\n\nconst targetPath = stringToPath('some.path')\n\nexport default defineMigration({\n title: ${JSON.stringify(migrationName)},\n${\n documentTypes.length > 0\n ? ` documentTypes: [${documentTypes.map((t) => JSON.stringify(t)).join(', ')}],\\n`\n : ''\n}\n migrate: {\n string(node, path, ctx) {\n if (pathsAreEqual(path, targetPath)) {\n return set([\n {\n style: 'normal',\n _type: 'block',\n children: [\n {\n _type: 'span',\n marks: [],\n text: node,\n },\n ],\n markDefs: [],\n },\n ])\n }\n },\n },\n})\n`\n"],"names":["stringToPTE","documentTypes","migrationName","JSON","stringify","length","map","t","join"],"mappings":"AAAA,OAAO,MAAMA,cAAc,CAAC,EAC1BC,aAAa,EACbC,aAAa,EAId,GAAK,CAAC;;;;;;SAME,EAAEC,KAAKC,SAAS,CAACF,eAAe;AACzC,EACED,cAAcI,MAAM,GAAG,IACnB,CAAC,kBAAkB,EAAEJ,cAAcK,GAAG,CAAC,CAACC,IAAMJ,KAAKC,SAAS,CAACG,IAAIC,IAAI,CAAC,MAAM,IAAI,CAAC,GACjF,GACL;;;;;;;;;;;;;;;;;;;;;;AAsBD,CAAC,CAAA"}