From ad9a2d215b2d1b87e7c58c5f9152568fcad830d3 Mon Sep 17 00:00:00 2001 From: MrCheater Date: Mon, 19 Jan 2026 17:22:00 +0300 Subject: [PATCH] feat: add support for "schemaName" option --- package-lock.json | 4 +- package.json | 2 +- src/commands/constants.ts | 9 ++++ src/commands/postgres/index.ts | 4 +- src/commands/postgres/setup.ts | 29 ++++++++++-- src/commands/postgres/sql.ts | 46 +++++++++++++++++-- src/commands/program.ts | 7 +-- src/commands/sqlite/index.ts | 4 +- src/commands/sqlite/setup.ts | 30 +++++++++++-- src/commands/sqlite/sql.ts | 46 +++++++++++++++++-- src/postgres/create-data-migration.ts | 11 ++++- src/postgres/create-initial-migration.ts | 11 ++++- src/postgres/create-migrations.ts | 6 ++- src/postgres/setup-tables.ts | 3 ++ src/sqlite/create-data-migration.test.ts | 47 +++++++++++--------- src/sqlite/create-data-migration.ts | 11 ++++- src/sqlite/create-initial-migration.test.ts | 49 ++++++++++++--------- src/sqlite/create-initial-migration.ts | 11 ++++- src/sqlite/create-migrations.ts | 6 ++- src/sqlite/setup-tables.ts | 1 + src/utils/get-full-table-name.ts | 12 +++++ src/utils/index.ts | 1 + 22 files changed, 267 insertions(+), 83 deletions(-) create mode 100644 src/utils/get-full-table-name.ts diff --git a/package-lock.json b/package-lock.json index 1fb1655..d0e9521 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@analtools/jsonormalize", - "version": "0.0.14", + "version": "0.0.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@analtools/jsonormalize", - "version": "0.0.14", + "version": "0.0.15", "license": "MIT", "dependencies": { "@electric-sql/pglite": "^0.3.15", diff --git a/package.json b/package.json index 72e3a5f..699e6ad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@analtools/jsonormalize", - "version": "0.0.14", + "version": "0.0.15", "description": "JSONormalize — Transform any JSON into a relational database schema. Automatically normalizes nested structures, detects relationships, and generates SQLite migrations. Perfect for rapid prototyping, data migrations, and structured data workflows.", "keywords": [ "json-normalize", diff --git a/src/commands/constants.ts b/src/commands/constants.ts index 7b52848..d374131 100644 --- a/src/commands/constants.ts +++ b/src/commands/constants.ts @@ -1,3 +1,5 @@ +export const description = `JSONormalize — Transform any JSON into a relational database schema. Automatically normalizes nested structures, detects relationships, and generates SQLite migrations. Perfect for rapid prototyping, data migrations, and structured data workflows.`; + export const requiredArgs = { jsonPath: { name: "", @@ -25,6 +27,13 @@ export const optionalArgs = Object.fromEntries( }; }; +export const options = { + schema: { + name: "--schema ", + description: "The name of the database schema", + }, +}; + export const commands = { sql: { name: (prefix: string) => `${prefix}:sql`, diff --git a/src/commands/postgres/index.ts b/src/commands/postgres/index.ts index c18830e..9b4f693 100644 --- a/src/commands/postgres/index.ts +++ b/src/commands/postgres/index.ts @@ -1,2 +1,2 @@ -export { setup } from "./setup"; -export { sql } from "./sql"; +export * from "./setup"; +export * from "./sql"; diff --git a/src/commands/postgres/setup.ts b/src/commands/postgres/setup.ts index cb07985..1e6ad4a 100644 --- a/src/commands/postgres/setup.ts +++ b/src/commands/postgres/setup.ts @@ -1,7 +1,7 @@ import type { ClientConfig } from "pg"; import { setupTables } from "../../postgres"; -import { commands, optionalArgs, requiredArgs } from "../constants"; +import { commands, optionalArgs, options, requiredArgs } from "../constants"; import { prepare } from "../prepare"; import { program } from "../program"; @@ -10,6 +10,7 @@ program .description(commands.setup.description) .argument(requiredArgs.jsonPath.name, requiredArgs.jsonPath.description) .argument(optionalArgs.dbPath.name, optionalArgs.dbPath.description) + .option(options.schema.name, options.schema.description) .option("--user ", "default process.env.PGUSER || process.env.USER") .option("--password ", "default process.env.PGPASSWORD") .option("--host ", "default process.env.PGHOST") @@ -63,7 +64,9 @@ program "--options ", "command-line options to be sent to the server", ) - .action(setup); + .action((...args: Parameters) => + setup(...parseArgs(...args)), + ); function getNumberOption(value: string | undefined): number | undefined { return value === undefined ? undefined : Number(value); @@ -77,7 +80,7 @@ function getSslOption(value: any): ClientConfig["ssl"] { } } -export async function setup( +function parseArgs( jsonPath: string, dbPath: string | undefined, options: { @@ -98,8 +101,11 @@ export async function setup( clientEncoding?: string; fallbackApplicationName?: string; options?: string; + schema?: string; } = {}, -) { +): Parameters { + const schemaName = options.schema; + const config: ClientConfig | undefined = dbPath === undefined && Object.keys(options).length ? { @@ -129,6 +135,20 @@ export async function setup( } : undefined; + return [{ jsonPath, dbPath, config, schemaName }]; +} + +export async function setup({ + config, + dbPath, + jsonPath, + schemaName, +}: { + jsonPath: string; + dbPath?: string | undefined; + config?: ClientConfig | undefined; + schemaName?: string | undefined; +}) { const { data, prefix } = await prepare(jsonPath); await setupTables({ @@ -136,5 +156,6 @@ export async function setup( path: dbPath, data, prefix, + schemaName, }); } diff --git a/src/commands/postgres/sql.ts b/src/commands/postgres/sql.ts index 1844457..0f67a48 100644 --- a/src/commands/postgres/sql.ts +++ b/src/commands/postgres/sql.ts @@ -2,7 +2,7 @@ import * as fs from "node:fs"; import { EOL } from "node:os"; import { createMigrations } from "../../postgres"; -import { commands, requiredArgs } from "../constants"; +import { commands, options, requiredArgs } from "../constants"; import { prepare } from "../prepare"; import { program } from "../program"; @@ -11,15 +11,53 @@ program .description(commands.sql.description) .argument(requiredArgs.jsonPath.name, requiredArgs.jsonPath.description) .argument(requiredArgs.sqlPath.name, requiredArgs.sqlPath.description) - .action(sql); + .option(options.schema.name, options.schema.description) + .action((...args: Parameters) => + writeSqlScriptToFile(...parseArgs(...args)), + ); -export async function sql(jsonPath: string, sqlPath: string) { +function parseArgs( + jsonPath: string, + sqlPath: string, + { schema: schemaName }: { schema?: string } = {}, +): Parameters { + return [ + { + jsonPath, + sqlPath, + schemaName, + }, + ]; +} + +export async function getSqlScript({ + jsonPath, + schemaName, +}: { + jsonPath: string; + schemaName?: string | undefined; +}) { const { data, prefix } = await prepare(jsonPath); const { initialMigration, dataMigration } = createMigrations({ prefix, data, + schemaName, }); - fs.writeFileSync(sqlPath, `${initialMigration}${EOL}${EOL}${dataMigration}`); + return `${initialMigration}${EOL}${EOL}${dataMigration}`; +} + +export async function writeSqlScriptToFile({ + jsonPath, + sqlPath, + schemaName, +}: { + jsonPath: string; + sqlPath: string; + schemaName?: string | undefined; +}) { + const sqlScript = await getSqlScript({ jsonPath, schemaName }); + + fs.writeFileSync(sqlPath, sqlScript); } diff --git a/src/commands/program.ts b/src/commands/program.ts index 00eccf5..137b73c 100644 --- a/src/commands/program.ts +++ b/src/commands/program.ts @@ -1,9 +1,6 @@ import { Command } from "commander"; +import { description } from "./constants"; export const program = new Command(); -program - .name("jsonormalize") - .description( - `JSONormalize — Transform any JSON into a relational database schema. Automatically normalizes nested structures, detects relationships, and generates SQLite migrations. Perfect for rapid prototyping, data migrations, and structured data workflows.`, - ); +program.name("jsonormalize").description(description); diff --git a/src/commands/sqlite/index.ts b/src/commands/sqlite/index.ts index c18830e..9b4f693 100644 --- a/src/commands/sqlite/index.ts +++ b/src/commands/sqlite/index.ts @@ -1,2 +1,2 @@ -export { setup } from "./setup"; -export { sql } from "./sql"; +export * from "./setup"; +export * from "./sql"; diff --git a/src/commands/sqlite/setup.ts b/src/commands/sqlite/setup.ts index 74acacb..5020cfe 100644 --- a/src/commands/sqlite/setup.ts +++ b/src/commands/sqlite/setup.ts @@ -1,5 +1,5 @@ import { setupTables } from "../../sqlite"; -import { commands, optionalArgs, requiredArgs } from "../constants"; +import { commands, optionalArgs, options, requiredArgs } from "../constants"; import { prepare } from "../prepare"; import { program } from "../program"; @@ -8,14 +8,38 @@ program .description(commands.setup.description) .argument(requiredArgs.jsonPath.name, requiredArgs.jsonPath.description) .argument(optionalArgs.dbPath.name, optionalArgs.dbPath.description) - .action(setup); + .option(options.schema.name, options.schema.description) + .action((...args: Parameters) => + setup(...parseArgs(...args)), + ); -export async function setup(jsonPath: string, dbPath: string) { +function parseArgs( + jsonPath: string, + dbPath: string | undefined, + options: { + schema?: string; + } = {}, +): Parameters { + const schemaName = options.schema; + + return [{ jsonPath, dbPath, schemaName }]; +} + +export async function setup({ + jsonPath, + dbPath, + schemaName, +}: { + jsonPath: string; + dbPath?: string | undefined; + schemaName?: string | string; +}) { const { data, prefix } = await prepare(jsonPath); await setupTables({ path: dbPath, data, prefix, + schemaName, }); } diff --git a/src/commands/sqlite/sql.ts b/src/commands/sqlite/sql.ts index 3ce6bdf..95dde8f 100644 --- a/src/commands/sqlite/sql.ts +++ b/src/commands/sqlite/sql.ts @@ -2,7 +2,7 @@ import * as fs from "node:fs"; import { EOL } from "node:os"; import { createMigrations } from "../../sqlite"; -import { commands, requiredArgs } from "../constants"; +import { commands, options, requiredArgs } from "../constants"; import { prepare } from "../prepare"; import { program } from "../program"; @@ -11,15 +11,53 @@ program .description(commands.sql.description) .argument(requiredArgs.jsonPath.name, requiredArgs.jsonPath.description) .argument(requiredArgs.sqlPath.name, requiredArgs.sqlPath.description) - .action(sql); + .option(options.schema.name, options.schema.description) + .action((...args: Parameters) => + writeSqlScriptToFile(...parseArgs(...args)), + ); -export async function sql(jsonPath: string, sqlPath: string) { +function parseArgs( + jsonPath: string, + sqlPath: string, + { schema: schemaName }: { schema?: string } = {}, +): Parameters { + return [ + { + jsonPath, + sqlPath, + schemaName, + }, + ]; +} + +export async function getSqlScript({ + jsonPath, + schemaName, +}: { + jsonPath: string; + schemaName?: string | undefined; +}) { const { data, prefix } = await prepare(jsonPath); const { initialMigration, dataMigration } = createMigrations({ prefix, data, + schemaName, }); - fs.writeFileSync(sqlPath, `${initialMigration}${EOL}${EOL}${dataMigration}`); + return `${initialMigration}${EOL}${EOL}${dataMigration}`; +} + +export async function writeSqlScriptToFile({ + jsonPath, + sqlPath, + schemaName, +}: { + jsonPath: string; + sqlPath: string; + schemaName?: string | undefined; +}) { + const sqlScript = await getSqlScript({ jsonPath, schemaName }); + + fs.writeFileSync(sqlPath, sqlScript); } diff --git a/src/postgres/create-data-migration.ts b/src/postgres/create-data-migration.ts index 2f004d2..11984f6 100644 --- a/src/postgres/create-data-migration.ts +++ b/src/postgres/create-data-migration.ts @@ -1,15 +1,22 @@ import { EOL } from "node:os"; import type { RelationalTable } from "../create-relational-structure"; +import { getFullTableName } from "../utils"; import { escapeValue } from "./escape-value"; -export function createDataMigration(tables: RelationalTable[]) { +export function createDataMigration({ + tables, + schemaName, +}: { + tables: RelationalTable[]; + schemaName?: string | undefined; +}): string { return tables .filter((table) => table.data.length > 0) .map((table) => { const keys = table.fields.map(({ key }) => key); return [ - `INSERT INTO ${table.name} (${keys.join(", ")}) VALUES`, + `INSERT INTO ${getFullTableName({ tableName: table.name, schemaName })} (${keys.join(", ")}) VALUES`, `${table.data .map((row) => { const values = keys.map((key) => row[key]); diff --git a/src/postgres/create-initial-migration.ts b/src/postgres/create-initial-migration.ts index d062cf5..c793277 100644 --- a/src/postgres/create-initial-migration.ts +++ b/src/postgres/create-initial-migration.ts @@ -2,14 +2,21 @@ import { EOL } from "node:os"; import type { RelationalTable } from "../create-relational-structure"; import { getForeignKeys, getPrimaryKeys } from "../create-relational-structure"; +import { getFullTableName } from "../utils"; import { getFieldType } from "./get-field-type"; -export function createInitialMigration(tables: RelationalTable[]): string { +export function createInitialMigration({ + tables, + schemaName, +}: { + tables: RelationalTable[]; + schemaName?: string | undefined; +}): string { return tables .map((table) => { const foreignKeys = getForeignKeys(table); return [ - `CREATE TABLE ${table.name} (`, + `CREATE TABLE ${getFullTableName({ tableName: table.name, schemaName })} (`, [ ...table.fields.map( (field) => diff --git a/src/postgres/create-migrations.ts b/src/postgres/create-migrations.ts index ecb5994..026480a 100644 --- a/src/postgres/create-migrations.ts +++ b/src/postgres/create-migrations.ts @@ -6,14 +6,16 @@ import { createInitialMigration } from "./create-initial-migration"; export function createMigrations({ prefix, data, + schemaName, }: { prefix: string; data: unknown; + schemaName?: string | undefined; }) { const tables = createRelationalStructure(prefix, normalize(data)); return { - initialMigration: createInitialMigration(tables), - dataMigration: createDataMigration(tables), + initialMigration: createInitialMigration({ tables, schemaName }), + dataMigration: createDataMigration({ tables, schemaName }), }; } diff --git a/src/postgres/setup-tables.ts b/src/postgres/setup-tables.ts index d2e30c9..0ccf77e 100644 --- a/src/postgres/setup-tables.ts +++ b/src/postgres/setup-tables.ts @@ -8,15 +8,18 @@ export async function setupTables({ path, prefix, data, + schemaName, }: { config?: ClientConfig; path?: string; prefix: string; data: unknown; + schemaName?: string | undefined; }) { const { initialMigration, dataMigration } = createMigrations({ prefix, data, + schemaName, }); if (config) { diff --git a/src/sqlite/create-data-migration.test.ts b/src/sqlite/create-data-migration.test.ts index a48f3cd..5bd3f9d 100644 --- a/src/sqlite/create-data-migration.test.ts +++ b/src/sqlite/create-data-migration.test.ts @@ -7,70 +7,70 @@ import { createDataMigration } from "./create-data-migration"; describe("sqlite/create-data-migration", () => { it("should handle empty input array", () => { expect( - createDataMigration(createRelationalStructure("test", [])), + createDataMigration({ tables: createRelationalStructure("test", []) }), ).toMatchSnapshot(); }); it("should handle empty arrays", () => { expect( - createDataMigration( - createRelationalStructure( + createDataMigration({ + tables: createRelationalStructure( "test", normalize([ { value: "a", items: [] }, { value: "b", items: [] }, ]), ), - ), + }), ).toMatchSnapshot(); }); it("should create a simple table with integer values", () => { expect( - createDataMigration( - createRelationalStructure("test", normalize([1, 2, 3])), - ), + createDataMigration({ + tables: createRelationalStructure("test", normalize([1, 2, 3])), + }), ).toMatchSnapshot(); }); it("should create a table with mixed integer and real values", () => { expect( - createDataMigration( - createRelationalStructure("test", [ + createDataMigration({ + tables: createRelationalStructure("test", [ { item: 1 }, { item: 2.5 }, { item: 3 }, ]), - ), + }), ).toMatchSnapshot(); }); it("should create a table with nullable fields when null values are present", () => { expect( - createDataMigration( - createRelationalStructure("test", normalize([1, null, 3])), - ), + createDataMigration({ + tables: createRelationalStructure("test", normalize([1, null, 3])), + }), ).toMatchSnapshot(); }); it("should create nested tables for arrays with foreign key relationships", () => { expect( - createDataMigration( - createRelationalStructure( + createDataMigration({ + tables: createRelationalStructure( "test", normalize([ { value: "a", items: [1, 2, 3] }, { value: "b", items: [4, 5, 6] }, ]), ), - ), + }), ).toMatchSnapshot(); }); it("should handle deeply nested arrays with multiple levels of relationships", () => { expect( - createDataMigration( - createRelationalStructure( + createDataMigration({ + tables: createRelationalStructure( "test", normalize([ { @@ -79,15 +79,18 @@ describe("sqlite/create-data-migration", () => { }, ]), ), - ), + }), ).toMatchSnapshot(); }); it("should generate migration for objects with different property names", () => { expect( - createDataMigration( - createRelationalStructure("test", normalize([{ a: "a" }, { b: "b" }])), - ), + createDataMigration({ + tables: createRelationalStructure( + "test", + normalize([{ a: "a" }, { b: "b" }]), + ), + }), ).toMatchSnapshot(); }); }); diff --git a/src/sqlite/create-data-migration.ts b/src/sqlite/create-data-migration.ts index 2f004d2..c011c89 100644 --- a/src/sqlite/create-data-migration.ts +++ b/src/sqlite/create-data-migration.ts @@ -1,15 +1,22 @@ import { EOL } from "node:os"; import type { RelationalTable } from "../create-relational-structure"; +import { getFullTableName } from "../utils"; import { escapeValue } from "./escape-value"; -export function createDataMigration(tables: RelationalTable[]) { +export function createDataMigration({ + tables, + schemaName, +}: { + tables: RelationalTable[]; + schemaName?: string | undefined; +}) { return tables .filter((table) => table.data.length > 0) .map((table) => { const keys = table.fields.map(({ key }) => key); return [ - `INSERT INTO ${table.name} (${keys.join(", ")}) VALUES`, + `INSERT INTO ${getFullTableName({ tableName: table.name, schemaName })} (${keys.join(", ")}) VALUES`, `${table.data .map((row) => { const values = keys.map((key) => row[key]); diff --git a/src/sqlite/create-initial-migration.test.ts b/src/sqlite/create-initial-migration.test.ts index 97b87cc..8958f07 100644 --- a/src/sqlite/create-initial-migration.test.ts +++ b/src/sqlite/create-initial-migration.test.ts @@ -7,72 +7,74 @@ import { createInitialMigration } from "./create-initial-migration"; describe("sqlite/create-initial-migration", () => { it("should handle empty input array", () => { expect( - createInitialMigration(createRelationalStructure("test", normalize([]))), + createInitialMigration({ + tables: createRelationalStructure("test", normalize([])), + }), ).toMatchSnapshot(); }); it("should handle empty arrays", () => { expect( - createInitialMigration( - createRelationalStructure("test", [ + createInitialMigration({ + tables: createRelationalStructure("test", [ { value: "a", items: [] }, { value: "b", items: [] }, ]), - ), + }), ).toMatchSnapshot(); }); it("should create a simple table with integer values", () => { expect( - createInitialMigration( - createRelationalStructure( + createInitialMigration({ + tables: createRelationalStructure( "test", normalize([{ value: 1 }, { value: 2 }, { value: 3 }]), ), - ), + }), ).toMatchSnapshot(); }); it("should create a table with mixed integer and real values", () => { expect( - createInitialMigration( - createRelationalStructure( + createInitialMigration({ + tables: createRelationalStructure( "test", normalize([{ value: 1 }, { value: 2.5 }, { value: 3 }]), ), - ), + }), ).toMatchSnapshot(); }); it("should create a table with nullable fields when null values are present", () => { expect( - createInitialMigration( - createRelationalStructure( + createInitialMigration({ + tables: createRelationalStructure( "test", normalize([{ value: 1 }, { value: null }, { value: 3 }]), ), - ), + }), ).toMatchSnapshot(); }); it("should create nested tables for arrays with foreign key relationships", () => { expect( - createInitialMigration( - createRelationalStructure( + createInitialMigration({ + tables: createRelationalStructure( "test", normalize([ { value: "a", items: [{ value: 1 }, { value: 2 }, { value: 3 }] }, { value: "b", items: [{ value: 4 }, { value: 5 }, { value: 6 }] }, ]), ), - ), + }), ).toMatchSnapshot(); }); it("should handle deeply nested arrays with multiple levels of relationships", () => { expect( - createInitialMigration( - createRelationalStructure( + createInitialMigration({ + tables: createRelationalStructure( "test", normalize([ { @@ -81,15 +83,18 @@ describe("sqlite/create-initial-migration", () => { }, ]), ), - ), + }), ).toMatchSnapshot(); }); it("should generate migration for objects with different property names", () => { expect( - createInitialMigration( - createRelationalStructure("test", normalize([{ a: "a" }, { b: "b" }])), - ), + createInitialMigration({ + tables: createRelationalStructure( + "test", + normalize([{ a: "a" }, { b: "b" }]), + ), + }), ).toMatchSnapshot(); }); }); diff --git a/src/sqlite/create-initial-migration.ts b/src/sqlite/create-initial-migration.ts index d062cf5..c793277 100644 --- a/src/sqlite/create-initial-migration.ts +++ b/src/sqlite/create-initial-migration.ts @@ -2,14 +2,21 @@ import { EOL } from "node:os"; import type { RelationalTable } from "../create-relational-structure"; import { getForeignKeys, getPrimaryKeys } from "../create-relational-structure"; +import { getFullTableName } from "../utils"; import { getFieldType } from "./get-field-type"; -export function createInitialMigration(tables: RelationalTable[]): string { +export function createInitialMigration({ + tables, + schemaName, +}: { + tables: RelationalTable[]; + schemaName?: string | undefined; +}): string { return tables .map((table) => { const foreignKeys = getForeignKeys(table); return [ - `CREATE TABLE ${table.name} (`, + `CREATE TABLE ${getFullTableName({ tableName: table.name, schemaName })} (`, [ ...table.fields.map( (field) => diff --git a/src/sqlite/create-migrations.ts b/src/sqlite/create-migrations.ts index ecb5994..026480a 100644 --- a/src/sqlite/create-migrations.ts +++ b/src/sqlite/create-migrations.ts @@ -6,14 +6,16 @@ import { createInitialMigration } from "./create-initial-migration"; export function createMigrations({ prefix, data, + schemaName, }: { prefix: string; data: unknown; + schemaName?: string | undefined; }) { const tables = createRelationalStructure(prefix, normalize(data)); return { - initialMigration: createInitialMigration(tables), - dataMigration: createDataMigration(tables), + initialMigration: createInitialMigration({ tables, schemaName }), + dataMigration: createDataMigration({ tables, schemaName }), }; } diff --git a/src/sqlite/setup-tables.ts b/src/sqlite/setup-tables.ts index 5cbf119..ed66263 100644 --- a/src/sqlite/setup-tables.ts +++ b/src/sqlite/setup-tables.ts @@ -11,6 +11,7 @@ export async function setupTables({ path?: string; prefix: string; data: unknown; + schemaName?: string | undefined; }) { const { initialMigration, dataMigration } = createMigrations({ prefix, diff --git a/src/utils/get-full-table-name.ts b/src/utils/get-full-table-name.ts new file mode 100644 index 0000000..086e2c5 --- /dev/null +++ b/src/utils/get-full-table-name.ts @@ -0,0 +1,12 @@ +export function getFullTableName({ + tableName, + schemaName, +}: { + tableName: string; + schemaName?: string | undefined; +}): string { + if (schemaName !== undefined) { + return `${schemaName}.${tableName}`; + } + return tableName; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index fd7a222..6b7711d 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,4 @@ +export * from "./get-full-table-name"; export * from "./is-array-of-arrays"; export * from "./is-array-of-primitives"; export * from "./is-dictionary";