nuxt-google-sheets-import 0.1.4 → 0.1.7

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 (28) hide show
  1. package/README.md +110 -123
  2. package/dist/module.d.mts +0 -1
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +21 -18
  5. package/dist/runtime/components/GoogleSheetsImportExecute.vue +3 -0
  6. package/dist/runtime/components/GoogleSheetsImportExport.d.vue.ts +3 -0
  7. package/dist/runtime/components/GoogleSheetsImportExport.vue +196 -0
  8. package/dist/runtime/components/GoogleSheetsImportExport.vue.d.ts +3 -0
  9. package/dist/runtime/components/GoogleSheetsImportSchemaGuide.vue +29 -48
  10. package/dist/runtime/components/GoogleSheetsImportSource.vue +3 -0
  11. package/dist/runtime/pages/google-sheets-import.vue +34 -3
  12. package/dist/runtime/server/api/collection-type.get.js +1 -2
  13. package/dist/runtime/server/api/schema-columns.get.js +5 -6
  14. package/dist/runtime/server/api/values.post.js +2 -3
  15. package/dist/runtime/server/api/write.post.js +2 -3
  16. package/dist/runtime/server/utils/collectionType.d.ts +1 -1
  17. package/dist/runtime/server/utils/collectionType.js +39 -30
  18. package/dist/runtime/server/utils/schemaColumns.js +5 -2
  19. package/dist/runtime/server/utils/transform.js +1 -42
  20. package/dist/runtime/utils/clipboard.d.ts +15 -0
  21. package/dist/runtime/utils/clipboard.js +12 -0
  22. package/dist/runtime/utils/delimited.d.ts +2 -0
  23. package/dist/runtime/utils/delimited.js +9 -0
  24. package/dist/runtime/utils/pathMapping.d.ts +4 -0
  25. package/dist/runtime/utils/pathMapping.js +86 -0
  26. package/package.json +1 -1
  27. package/dist/runtime/import/schemas.d.ts +0 -67
  28. package/dist/runtime/import/schemas.js +0 -35
@@ -1,6 +1,9 @@
1
1
  <script setup>
2
2
  import { computed, onMounted, ref, watch } from "vue";
3
+ import { useToast } from "#imports";
3
4
  import { useGoogleSheetsImport } from "../composables/useGoogleSheetsImport";
5
+ import { copyTextWithSuccessToast } from "../utils/clipboard";
6
+ import { toTsvRow } from "../utils/delimited";
4
7
  const props = defineProps({
5
8
  initialSchema: { type: String, required: false, default: "" }
6
9
  });
@@ -60,58 +63,36 @@ onMounted(async () => {
60
63
  await loadColumns(selectedSchema.value);
61
64
  }
62
65
  });
63
- function copyColumns() {
64
- const content = columns.value.join("\n");
65
- if (!content) {
66
- return;
67
- }
68
- navigator.clipboard.writeText(content);
69
- toast.add({
70
- title: "Copied",
66
+ async function copyColumns() {
67
+ await copyTextWithSuccessToast({
68
+ text: columns.value.join("\n"),
69
+ toast,
71
70
  description: "Column names copied to clipboard.",
72
- color: "success"
71
+ title: "Copied"
73
72
  });
74
73
  }
75
- function csvRow(values) {
76
- return values.map((value) => {
77
- const escaped = value.replaceAll('"', '""');
78
- return `"${escaped}"`;
79
- }).join(",");
80
- }
81
- function copyColumnsCsv() {
82
- const content = csvRow(columns.value);
83
- if (!content) {
84
- return;
85
- }
86
- navigator.clipboard.writeText(content);
87
- toast.add({
88
- title: "Copied",
89
- description: "Column names copied as a CSV row.",
90
- color: "success"
74
+ async function copyColumnsTsv() {
75
+ await copyTextWithSuccessToast({
76
+ text: toTsvRow(columns.value),
77
+ toast,
78
+ description: "Column names copied as a tab-separated row for Google Sheets.",
79
+ title: "Copied"
91
80
  });
92
81
  }
93
- function copyPageOverrideColumns() {
94
- const content = pageOverrideColumns.value.join("\n");
95
- if (!content) {
96
- return;
97
- }
98
- navigator.clipboard.writeText(content);
99
- toast.add({
100
- title: "Copied",
82
+ async function copyPageOverrideColumns() {
83
+ await copyTextWithSuccessToast({
84
+ text: pageOverrideColumns.value.join("\n"),
85
+ toast,
101
86
  description: "Page override column names copied to clipboard.",
102
- color: "success"
87
+ title: "Copied"
103
88
  });
104
89
  }
105
- function copyPageOverrideColumnsCsv() {
106
- const content = csvRow(pageOverrideColumns.value);
107
- if (!content) {
108
- return;
109
- }
110
- navigator.clipboard.writeText(content);
111
- toast.add({
112
- title: "Copied",
113
- description: "Page override column names copied as a CSV row.",
114
- color: "success"
90
+ async function copyPageOverrideColumnsTsv() {
91
+ await copyTextWithSuccessToast({
92
+ text: toTsvRow(pageOverrideColumns.value),
93
+ toast,
94
+ description: "Page override column names copied as a tab-separated row for Google Sheets.",
95
+ title: "Copied"
115
96
  });
116
97
  }
117
98
  </script>
@@ -169,11 +150,11 @@ function copyPageOverrideColumnsCsv() {
169
150
  @click="copyColumns"
170
151
  />
171
152
  <UButton
172
- label="Copy as CSV row"
153
+ label="Copy as tab-separated row"
173
154
  icon="i-heroicons-table-cells-20-solid"
174
155
  color="neutral"
175
156
  variant="subtle"
176
- @click="copyColumnsCsv"
157
+ @click="copyColumnsTsv"
177
158
  />
178
159
  </div>
179
160
  <pre class="text-xs whitespace-pre-wrap">{{ columns.join("\n") }}</pre>
@@ -199,11 +180,11 @@ function copyPageOverrideColumnsCsv() {
199
180
  @click="copyPageOverrideColumns"
200
181
  />
201
182
  <UButton
202
- label="Copy overrides as CSV row"
183
+ label="Copy overrides as tab-separated row"
203
184
  icon="i-heroicons-table-cells-20-solid"
204
185
  color="neutral"
205
186
  variant="subtle"
206
- @click="copyPageOverrideColumnsCsv"
187
+ @click="copyPageOverrideColumnsTsv"
207
188
  />
208
189
  </div>
209
190
  <pre class="text-xs whitespace-pre-wrap">{{ pageOverrideColumns.join("\n") }}</pre>
@@ -1,5 +1,8 @@
1
1
  <script setup>
2
2
  import { z } from "zod";
3
+ import { useGoogleSheetsImportWorkflow } from "../composables/useGoogleSheetsImportWorkflow";
4
+ import { useToast } from "#imports";
5
+ import { watch } from "vue";
3
6
  const { googleSheets } = defineProps({
4
7
  googleSheets: { type: Array, required: true }
5
8
  });
@@ -4,11 +4,42 @@ const sheetsList = ref([
4
4
  { id: "1NKS0cTX6u5urtgQ3Q4Z2motiR2-9JmyPxcd05yVc1bc", label: "Metzner" },
5
5
  { id: "1tGZCEoiikXfg3mOpfVWWTS1SSSsj18xv6Z3owrnnt4s", label: "Example Sheet" }
6
6
  ]);
7
+ const items = ref([
8
+ {
9
+ label: "Setup Google Sheet",
10
+ icon: "i-lucide-layout-dashboard",
11
+ slot: "sheet"
12
+ },
13
+ {
14
+ label: "Import data",
15
+ icon: "i-lucide-upload",
16
+ slot: "import"
17
+ },
18
+ {
19
+ label: "Export data",
20
+ icon: "i-lucide-download",
21
+ slot: "export"
22
+ }
23
+ ]);
7
24
  </script>
8
25
 
9
26
  <template>
10
- <UContainer>
11
- <GoogleSheetsImportSchemaGuide />
12
- <GoogleSheetsImportSource :google-sheets="sheetsList" />
27
+ <UContainer class="max-w-36">
28
+ <UTabs
29
+ :items="items"
30
+ variant="link"
31
+ color="neutral"
32
+ class="w-full"
33
+ >
34
+ <template #sheet>
35
+ <GoogleSheetsImportSchemaGuide :initial-schema="'Example Sheet'" />
36
+ </template>
37
+ <template #import>
38
+ <GoogleSheetsImportSource :google-sheets="sheetsList" />
39
+ </template>
40
+ <template #export>
41
+ <GoogleSheetsImportExport />
42
+ </template>
43
+ </UTabs>
13
44
  </UContainer>
14
45
  </template>
@@ -9,8 +9,7 @@ export default defineEventHandler(async (event) => {
9
9
  const { schema } = await getValidatedQuery(event, (query) => querySchema.parse(query));
10
10
  const config = useRuntimeConfig(event);
11
11
  const moduleConfig = config.googleSheetsImport;
12
- const fromConfig = moduleConfig.collectionTypeBySchema ?? {};
13
- const collectionType = await resolveCollectionTypeBySchema(schema, fromConfig);
12
+ const collectionType = await resolveCollectionTypeBySchema(schema);
14
13
  const baseContentDir = collectionType === "page" ? "content" : collectionType === "data" ? "content/data" : moduleConfig.defaultContentDir;
15
14
  return {
16
15
  schema: schema ?? null,
@@ -2,15 +2,13 @@ import { z } from "zod";
2
2
  import { resolveCollectionTypeBySchema } from "../utils/collectionType.js";
3
3
  import { getSchemaColumns, PAGE_SCHEMA_OVERRIDE_COLUMNS } from "../utils/schemaColumns.js";
4
4
  import { getValidatedQuery, defineEventHandler, createError } from "h3";
5
- import { useRuntimeConfig } from "#imports";
5
+ import { googleSheetsImportSchemas } from "#imports";
6
6
  const querySchema = z.object({
7
7
  schema: z.string().optional()
8
8
  });
9
9
  export default defineEventHandler(async (event) => {
10
10
  const { schema } = await getValidatedQuery(event, (query) => querySchema.parse(query));
11
- const config = useRuntimeConfig(event);
12
- const moduleConfig = config.googleSheetsImport;
13
- const schemaMap = {};
11
+ const schemaMap = googleSheetsImportSchemas ?? {};
14
12
  const availableSchemas = Object.keys(schemaMap).sort((left, right) => left.localeCompare(right));
15
13
  if (!schema) {
16
14
  return {
@@ -21,7 +19,7 @@ export default defineEventHandler(async (event) => {
21
19
  pageOverrideColumns: []
22
20
  };
23
21
  }
24
- const collectionType = await resolveCollectionTypeBySchema(schema, moduleConfig.collectionTypeBySchema ?? {});
22
+ const collectionType = await resolveCollectionTypeBySchema(schema);
25
23
  const selectedSchema = schemaMap[schema];
26
24
  if (!selectedSchema) {
27
25
  throw createError({
@@ -29,10 +27,11 @@ export default defineEventHandler(async (event) => {
29
27
  statusMessage: `Unknown schema: ${schema}`
30
28
  });
31
29
  }
30
+ const columns = getSchemaColumns(selectedSchema);
32
31
  return {
33
32
  schema,
34
33
  schemas: availableSchemas,
35
- columns: getSchemaColumns(selectedSchema),
34
+ columns,
36
35
  collectionType,
37
36
  pageOverrideColumns: collectionType === "page" ? PAGE_SCHEMA_OVERRIDE_COLUMNS : []
38
37
  };
@@ -1,8 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { transformAndValidateRows } from "../utils/transform.js";
3
3
  import { readBody, defineEventHandler, createError } from "h3";
4
- import { useRuntimeConfig } from "#imports";
5
- import { schemas } from "../../import/schemas.js";
4
+ import { useRuntimeConfig, googleSheetsImportSchemas } from "#imports";
6
5
  const bodySchema = z.object({
7
6
  spreadsheetId: z.string().length(44),
8
7
  sheetTitle: z.string().min(1),
@@ -19,7 +18,7 @@ export default defineEventHandler(async (event) => {
19
18
  const encodedRange = encodeURIComponent(`${body.sheetTitle}!${body.range}`);
20
19
  const googleResponse = await $fetch(`https://sheets.googleapis.com/v4/spreadsheets/${body.spreadsheetId}/values/${encodedRange}?key=${apiKey}`);
21
20
  const values = googleResponse.values ?? [];
22
- const schemaMap = schemas;
21
+ const schemaMap = googleSheetsImportSchemas ?? {};
23
22
  const schema = schemaMap[body.schema];
24
23
  if (!schema) {
25
24
  throw createError({ statusCode: 400, statusMessage: `Unknown schema: ${body.schema}` });
@@ -25,7 +25,7 @@ function resolveContentDirByCollectionType(collectionType, schemaKey, fallback)
25
25
  }
26
26
  const normalizedSchemaKey = schemaKey.trim();
27
27
  console.warn(
28
- `[google-sheets-import] No collection type mapping found for schema "${normalizedSchemaKey}". Using fallback content directory "${fallback}". Add googleSheetsImport.collectionTypeBySchema["` + normalizedSchemaKey + '"] in nuxt.config.ts to route writes automatically.'
28
+ `[google-sheets-import] No collection type mapping found for schema "${normalizedSchemaKey}". Using fallback content directory "${fallback}". Ensure the matching Nuxt Content collection is defined with type "page" or "data" in content.config.ts.`
29
29
  );
30
30
  return fallback;
31
31
  }
@@ -33,8 +33,7 @@ export default defineEventHandler(async (event) => {
33
33
  const body = bodySchema.parse(await readBody(event));
34
34
  const config = useRuntimeConfig(event);
35
35
  const moduleConfig = config.googleSheetsImport;
36
- const mappedInConfig = moduleConfig.collectionTypeBySchema ?? {};
37
- const resolvedCollectionType = await resolveCollectionTypeBySchema(body.schema, mappedInConfig);
36
+ const resolvedCollectionType = await resolveCollectionTypeBySchema(body.schema);
38
37
  const resolvedContentDir = body.contentDir ?? resolveContentDirByCollectionType(resolvedCollectionType, body.schema, moduleConfig.defaultContentDir);
39
38
  const logs = [];
40
39
  const summary = {
@@ -1,3 +1,3 @@
1
1
  type CollectionType = 'page' | 'data';
2
- export declare function resolveCollectionTypeBySchema(schemaKey: string | undefined, collectionTypeBySchemaFromConfig: Record<string, CollectionType>): Promise<CollectionType | 'unknown'>;
2
+ export declare function resolveCollectionTypeBySchema(schemaKey: string | undefined): Promise<CollectionType | 'unknown'>;
3
3
  export {};
@@ -12,46 +12,55 @@ function setCollectionType(map, key, type) {
12
12
  map[normalized] = type;
13
13
  }
14
14
  }
15
- async function readCollectionTypeBySchemaFromContentConfig() {
16
- if (cachedCollectionTypeBySchema) {
17
- return cachedCollectionTypeBySchema;
18
- }
15
+ function parseManifestSource(source) {
19
16
  const result = {};
20
- try {
21
- const contentConfigPath = path.resolve(process.cwd(), "content.config.ts");
22
- const source = await readFile(contentConfigPath, "utf-8");
23
- const collectionTypeMatches = source.matchAll(/(\w+)\s*:\s*defineCollection\([\s\S]{0,900}?type:\s*['"](page|data)['"]/g);
24
- for (const match of collectionTypeMatches) {
25
- const collectionName = match[1];
26
- const collectionType = match[2];
27
- if (collectionName) {
28
- setCollectionType(result, collectionName, collectionType);
29
- }
17
+ const schemas = /* @__PURE__ */ new Set();
18
+ const defaultExportIndex = source.indexOf("export default");
19
+ const manifestCollectionsSource = defaultExportIndex === -1 ? source : source.slice(defaultExportIndex);
20
+ const collectionTypeMatches = manifestCollectionsSource.matchAll(/"([^"\n]+)"\s*:\s*\{[\s\S]{0,500}?"type"\s*:\s*"(page|data)"/g);
21
+ for (const match of collectionTypeMatches) {
22
+ const collectionName = match[1];
23
+ const collectionType = match[2];
24
+ if (collectionName) {
25
+ schemas.add(collectionName);
26
+ setCollectionType(result, collectionName, collectionType);
30
27
  }
31
- const schemaTypeMatches = source.matchAll(/type:\s*['"](page|data)['"][\s\S]{0,900}?schema:\s*schemas\.(\w+)/g);
32
- for (const match of schemaTypeMatches) {
33
- const collectionType = match[1];
34
- const schemaKey = match[2];
35
- if (schemaKey) {
36
- setCollectionType(result, schemaKey, collectionType);
37
- }
28
+ }
29
+ return {
30
+ collectionTypeBySchema: result,
31
+ schemas: Array.from(schemas).sort((left, right) => left.localeCompare(right))
32
+ };
33
+ }
34
+ async function readManifestData() {
35
+ const candidates = [
36
+ path.resolve(process.cwd(), ".nuxt/content/manifest.ts"),
37
+ path.resolve(process.cwd(), ".nuxt/content/manifest.mjs")
38
+ ];
39
+ for (const manifestPath of candidates) {
40
+ try {
41
+ const source = await readFile(manifestPath, "utf-8");
42
+ return parseManifestSource(source);
43
+ } catch {
38
44
  }
39
- } catch {
40
- cachedCollectionTypeBySchema = {};
45
+ }
46
+ return {
47
+ collectionTypeBySchema: {},
48
+ schemas: []
49
+ };
50
+ }
51
+ async function readCollectionTypeBySchema() {
52
+ if (cachedCollectionTypeBySchema) {
41
53
  return cachedCollectionTypeBySchema;
42
54
  }
43
- cachedCollectionTypeBySchema = result;
55
+ const fromManifest = await readManifestData();
56
+ cachedCollectionTypeBySchema = fromManifest.collectionTypeBySchema;
44
57
  return cachedCollectionTypeBySchema;
45
58
  }
46
- export async function resolveCollectionTypeBySchema(schemaKey, collectionTypeBySchemaFromConfig) {
59
+ export async function resolveCollectionTypeBySchema(schemaKey) {
47
60
  if (!schemaKey) {
48
61
  return "unknown";
49
62
  }
50
- const mappedInContentConfig = await readCollectionTypeBySchemaFromContentConfig();
51
- const map = {
52
- ...mappedInContentConfig,
53
- ...collectionTypeBySchemaFromConfig
54
- };
63
+ const map = await readCollectionTypeBySchema();
55
64
  const normalizedSchemaKey = schemaKey.trim();
56
65
  const collectionType = normalizeSchemaKey(normalizedSchemaKey).map((key) => map[key]).find((value) => value === "page" || value === "data");
57
66
  return collectionType ?? "unknown";
@@ -66,8 +66,11 @@ function collectSchemaColumns(schema, prefix = "") {
66
66
  const arrayPrefix = `${prefix}[0]`;
67
67
  const elementCandidate = getDefValue(unwrapped, "element");
68
68
  const arrayElement = isZodType(elementCandidate) ? elementCandidate : null;
69
- const nested = arrayElement ? collectSchemaColumns(arrayElement, arrayPrefix) : [];
70
- return nested.length ? nested : [arrayPrefix];
69
+ if (arrayElement && getObjectShape(arrayElement)) {
70
+ const nested = collectSchemaColumns(arrayElement, arrayPrefix);
71
+ return nested.length ? nested : [arrayPrefix];
72
+ }
73
+ return prefix ? [prefix] : [arrayPrefix];
71
74
  }
72
75
  const objectShape = getObjectShape(unwrapped);
73
76
  if (objectShape) {
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { parseHeaderPath, setDeep } from "../../utils/pathMapping.js";
2
3
  function isZodType(value) {
3
4
  return typeof value === "object" && value !== null && "_def" in value;
4
5
  }
@@ -47,48 +48,6 @@ function hasWrapper(schema, wrapper) {
47
48
  }
48
49
  return false;
49
50
  }
50
- function parseHeaderPath(header) {
51
- const tokens = [];
52
- const parts = header.split(".");
53
- for (const part of parts) {
54
- const matches = part.matchAll(/([^[]+)|(\[(\d+)\])/g);
55
- for (const match of matches) {
56
- if (match[1]) {
57
- tokens.push(match[1]);
58
- }
59
- if (match[3]) {
60
- tokens.push(Number.parseInt(match[3], 10));
61
- }
62
- }
63
- }
64
- return tokens;
65
- }
66
- function setDeep(target, path, value) {
67
- if (!path.length) {
68
- return;
69
- }
70
- let cursor = target;
71
- for (let index = 0; index < path.length; index++) {
72
- const key = path[index];
73
- if (key === void 0) {
74
- return;
75
- }
76
- const isLast = index === path.length - 1;
77
- const nextKey = path[index + 1];
78
- if (isLast) {
79
- cursor[key] = value;
80
- return;
81
- }
82
- if (cursor[key] === void 0) {
83
- cursor[key] = typeof nextKey === "number" ? [] : {};
84
- }
85
- const nextCursor = cursor[key];
86
- if (!nextCursor || typeof nextCursor !== "object") {
87
- return;
88
- }
89
- cursor = nextCursor;
90
- }
91
- }
92
51
  function getObjectShape(schema) {
93
52
  const unwrapped = unwrapSchema(schema);
94
53
  if (!unwrapped) {
@@ -0,0 +1,15 @@
1
+ interface ToastLike {
2
+ add: (payload: {
3
+ title?: string;
4
+ description?: string;
5
+ color?: 'success' | 'error' | 'warning' | 'info' | 'neutral';
6
+ }) => void;
7
+ }
8
+ interface CopyTextWithToastOptions {
9
+ text: string;
10
+ toast: ToastLike;
11
+ description: string;
12
+ title?: string;
13
+ }
14
+ export declare function copyTextWithSuccessToast(options: CopyTextWithToastOptions): Promise<boolean>;
15
+ export {};
@@ -0,0 +1,12 @@
1
+ export async function copyTextWithSuccessToast(options) {
2
+ if (!options.text) {
3
+ return false;
4
+ }
5
+ await navigator.clipboard.writeText(options.text);
6
+ options.toast.add({
7
+ title: options.title ?? "Copied",
8
+ description: options.description,
9
+ color: "success"
10
+ });
11
+ return true;
12
+ }
@@ -0,0 +1,2 @@
1
+ export declare function toCsvRow(values: string[]): string;
2
+ export declare function toTsvRow(values: string[]): string;
@@ -0,0 +1,9 @@
1
+ export function toCsvRow(values) {
2
+ return values.map((value) => {
3
+ const escaped = value.replaceAll('"', '""');
4
+ return `"${escaped}"`;
5
+ }).join(",");
6
+ }
7
+ export function toTsvRow(values) {
8
+ return values.map((value) => value.replace(/[\t\r\n]+/g, " ")).join(" ");
9
+ }
@@ -0,0 +1,4 @@
1
+ export type PathSegment = string | number;
2
+ export declare function parseHeaderPath(header: string): PathSegment[];
3
+ export declare function setDeep(target: Record<string, unknown>, path: PathSegment[], value: unknown): void;
4
+ export declare function flattenRecordToStringMap(record: Record<string, unknown>, prefix?: string): Map<string, string>;
@@ -0,0 +1,86 @@
1
+ const EXCLUDED_EXPORT_PATHS = /* @__PURE__ */ new Set(["__hash__", "body"]);
2
+ export function parseHeaderPath(header) {
3
+ const tokens = [];
4
+ const parts = header.split(".");
5
+ for (const part of parts) {
6
+ const matches = part.matchAll(/([^[]+)|(\[(\d+)\])/g);
7
+ for (const match of matches) {
8
+ if (match[1]) {
9
+ tokens.push(match[1]);
10
+ }
11
+ if (match[3]) {
12
+ tokens.push(Number.parseInt(match[3], 10));
13
+ }
14
+ }
15
+ }
16
+ return tokens;
17
+ }
18
+ export function setDeep(target, path, value) {
19
+ if (!path.length) {
20
+ return;
21
+ }
22
+ let cursor = target;
23
+ for (let index = 0; index < path.length; index++) {
24
+ const key = path[index];
25
+ if (key === void 0) {
26
+ return;
27
+ }
28
+ const isLast = index === path.length - 1;
29
+ const nextKey = path[index + 1];
30
+ if (isLast) {
31
+ cursor[key] = value;
32
+ return;
33
+ }
34
+ if (cursor[key] === void 0) {
35
+ cursor[key] = typeof nextKey === "number" ? [] : {};
36
+ }
37
+ const nextCursor = cursor[key];
38
+ if (!nextCursor || typeof nextCursor !== "object") {
39
+ return;
40
+ }
41
+ cursor = nextCursor;
42
+ }
43
+ }
44
+ export function flattenRecordToStringMap(record, prefix = "") {
45
+ const out = /* @__PURE__ */ new Map();
46
+ for (const [key, value] of Object.entries(record)) {
47
+ const path = prefix ? `${prefix}.${key}` : key;
48
+ if (EXCLUDED_EXPORT_PATHS.has(path)) {
49
+ continue;
50
+ }
51
+ if (value === null || value === void 0) {
52
+ out.set(path, "");
53
+ continue;
54
+ }
55
+ if (Array.isArray(value)) {
56
+ if (value.every((item) => item === null || ["string", "number", "boolean"].includes(typeof item))) {
57
+ out.set(path, value.map((item) => item == null ? "" : String(item)).join(", "));
58
+ continue;
59
+ }
60
+ for (let index = 0; index < value.length; index++) {
61
+ const item = value[index];
62
+ const arrayPath = `${path}[${index}]`;
63
+ if (item && typeof item === "object" && !Array.isArray(item)) {
64
+ flattenRecordToStringMap(item, arrayPath).forEach((nestedValue, nestedKey) => {
65
+ out.set(nestedKey, nestedValue);
66
+ });
67
+ } else {
68
+ out.set(arrayPath, item == null ? "" : String(item));
69
+ }
70
+ }
71
+ continue;
72
+ }
73
+ if (value instanceof Date) {
74
+ out.set(path, value.toISOString());
75
+ continue;
76
+ }
77
+ if (typeof value === "object") {
78
+ flattenRecordToStringMap(value, path).forEach((nestedValue, nestedKey) => {
79
+ out.set(nestedKey, nestedValue);
80
+ });
81
+ continue;
82
+ }
83
+ out.set(path, String(value));
84
+ }
85
+ return out;
86
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-google-sheets-import",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "Schema-driven Google Sheets import module for Nuxt Content",
5
5
  "repository": "tribeweb/nuxt-google-sheets-import",
6
6
  "license": "MIT",
@@ -1,67 +0,0 @@
1
- import { z } from 'zod';
2
- export declare const machinesSmoke: z.ZodObject<{
3
- pageOrder: z.ZodNumber;
4
- modelId: z.ZodString;
5
- machineName: z.ZodString;
6
- cutRate: z.ZodNumber;
7
- featurePrimary: z.ZodOptional<z.ZodString>;
8
- }, z.core.$strip>;
9
- export declare const example: z.ZodObject<{
10
- slug: z.ZodString;
11
- pageOrder: z.ZodCoercedNumber<unknown>;
12
- number: z.ZodCoercedNumber<unknown>;
13
- string: z.ZodString;
14
- enumString: z.ZodEnum<{
15
- foo: "foo";
16
- bar: "bar";
17
- baz: "baz";
18
- }>;
19
- literalString: z.ZodLiteral<"foo">;
20
- unionString: z.ZodUnion<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>;
21
- unionStringArray: z.ZodArray<z.ZodUnion<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>>;
22
- exclusiveUnionString: z.ZodXor<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>;
23
- stringArray: z.ZodArray<z.ZodString>;
24
- boolean: z.ZodCoercedBoolean<unknown>;
25
- object: z.ZodObject<{
26
- key1: z.ZodString;
27
- key2: z.ZodString;
28
- }, z.core.$strip>;
29
- objectArray: z.ZodArray<z.ZodObject<{
30
- keyA: z.ZodString;
31
- keyB: z.ZodString;
32
- }, z.core.$strip>>;
33
- }, z.core.$strip>;
34
- export declare const schemas: {
35
- machinesSmoke: z.ZodObject<{
36
- pageOrder: z.ZodNumber;
37
- modelId: z.ZodString;
38
- machineName: z.ZodString;
39
- cutRate: z.ZodNumber;
40
- featurePrimary: z.ZodOptional<z.ZodString>;
41
- }, z.core.$strip>;
42
- example: z.ZodObject<{
43
- slug: z.ZodString;
44
- pageOrder: z.ZodCoercedNumber<unknown>;
45
- number: z.ZodCoercedNumber<unknown>;
46
- string: z.ZodString;
47
- enumString: z.ZodEnum<{
48
- foo: "foo";
49
- bar: "bar";
50
- baz: "baz";
51
- }>;
52
- literalString: z.ZodLiteral<"foo">;
53
- unionString: z.ZodUnion<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>;
54
- unionStringArray: z.ZodArray<z.ZodUnion<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>>;
55
- exclusiveUnionString: z.ZodXor<readonly [z.ZodLiteral<"foo">, z.ZodLiteral<"bar">]>;
56
- stringArray: z.ZodArray<z.ZodString>;
57
- boolean: z.ZodCoercedBoolean<unknown>;
58
- object: z.ZodObject<{
59
- key1: z.ZodString;
60
- key2: z.ZodString;
61
- }, z.core.$strip>;
62
- objectArray: z.ZodArray<z.ZodObject<{
63
- keyA: z.ZodString;
64
- keyB: z.ZodString;
65
- }, z.core.$strip>>;
66
- }, z.core.$strip>;
67
- };