@cerios/salesforce-sobjectly 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli.cjs +4 -4
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.mjs +5 -4
- package/dist/cli.mjs.map +1 -1
- package/dist/{codegen-BgDgU2RR.cjs → codegen-Bylrt2Ju.cjs} +207 -43
- package/dist/codegen-Bylrt2Ju.cjs.map +1 -0
- package/dist/{codegen-CSx0WAtK.mjs → codegen-C6MEYiWo.mjs} +211 -45
- package/dist/codegen-C6MEYiWo.mjs.map +1 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.d.cts +19 -4
- package/dist/codegen.d.mts +19 -4
- package/dist/codegen.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{sf-cli-DEVZQTR7.cjs → sf-cli-R6LHwqoo.cjs} +8 -5
- package/dist/{sf-cli-DEVZQTR7.cjs.map → sf-cli-R6LHwqoo.cjs.map} +1 -1
- package/dist/{sf-cli-CtWtdkJ0.mjs → sf-cli-_Ua-M_Zi.mjs} +8 -5
- package/dist/{sf-cli-CtWtdkJ0.mjs.map → sf-cli-_Ua-M_Zi.mjs.map} +1 -1
- package/package.json +1 -1
- package/sobjectly.config.schema.json +2 -2
- package/dist/codegen-BgDgU2RR.cjs.map +0 -1
- package/dist/codegen-CSx0WAtK.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ A type-safe Salesforce REST API client for TypeScript. It generates types for yo
|
|
|
9
9
|
|
|
10
10
|
## ✨ Key Features
|
|
11
11
|
|
|
12
|
-
- **Generated sObject types**: `sobjectly generate` reads describe metadata and writes a read type, a create input and an update input for every sObject. Required fields, restricted picklists and relationships all come from your org.
|
|
12
|
+
- **Generated sObject types**: `sobjectly generate` reads describe metadata and writes a read type, a create input and an update input for every sObject. Required fields, restricted picklists and relationships all come from your org. Picklists can also become named constants or enums, e.g. `CaseStatus.Working`.
|
|
13
13
|
- **Typed SOQL builder**: field names are checked and autocompleted. The query result only contains the fields you selected, so `record.Phone` is a compile error unless you selected `Phone`.
|
|
14
14
|
- **Relationship queries**: `selectRelated("Account", "Name")` and `selectChild("Contacts", c => c.select("Email"))` produce typed nested results.
|
|
15
15
|
- **The whole REST API**: sObject CRUD, upsert by external id, query and queryAll with pagination, SOSL, Composite, Composite Graph, sObject Tree, sObject Collections, invocable actions and Flows, the Tooling API, Apex REST and Bulk API 2.0. Anything else is reachable through `request<T>()`.
|
package/dist/cli.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_sf_cli = require("./sf-cli-
|
|
3
|
-
const require_codegen = require("./codegen-
|
|
2
|
+
const require_sf_cli = require("./sf-cli-R6LHwqoo.cjs");
|
|
3
|
+
const require_codegen = require("./codegen-Bylrt2Ju.cjs");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
let node_path = require("node:path");
|
|
6
6
|
let node_util = require("node:util");
|
|
@@ -24,7 +24,7 @@ Options for init (skip the matching questions; useful in scripts):
|
|
|
24
24
|
--sobjects <list> Comma-separated sObject API names
|
|
25
25
|
--auth <type> clientCredentials | sfCli | accessToken | jwtBearer
|
|
26
26
|
--target-org <alias> Salesforce CLI org alias (with --auth sfCli)
|
|
27
|
-
--picklists <mode> union | string
|
|
27
|
+
--picklists <mode> union | string | const | enum
|
|
28
28
|
--format <format> ts | json
|
|
29
29
|
-y, --yes Use the suggested answer for every other question (needs --api-version)
|
|
30
30
|
-f, --force Replace an existing config without asking
|
|
@@ -111,7 +111,7 @@ function initPreset(values) {
|
|
|
111
111
|
"jwtBearer"
|
|
112
112
|
]);
|
|
113
113
|
if (values["target-org"] !== void 0) preset.targetOrg = values["target-org"];
|
|
114
|
-
const picklists = oneOf("--picklists", values.picklists,
|
|
114
|
+
const picklists = oneOf("--picklists", values.picklists, require_codegen.PICKLIST_MODES);
|
|
115
115
|
const format = oneOf("--format", values.format, ["ts", "json"]);
|
|
116
116
|
return {
|
|
117
117
|
...preset,
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.cjs","names":["parseArgs","readlinePrompter","runInit","normalizeApiVersion","parseSObjects","resolve","existsSync","findConfigFiles","loadConfig","checkGenerated","generate"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/* oxlint-disable no-console */\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\n\nimport { normalizeApiVersion } from \"./api-version\";\nimport { checkGenerated, findConfigFiles, generate, loadConfig } from \"./codegen/index\";\nimport { type InitAnswers, parseSObjects, runInit } from \"./codegen/init\";\nimport { readlinePrompter } from \"./codegen/prompter\";\n\nconst HELP = `Usage: sobjectly <command> [options]\n\nCommands:\n init Create a sobjectly.config file by answering a few questions\n generate Generate TypeScript types for Salesforce sObjects (default)\n\nOptions for generate:\n -c, --config <path> Config file (default: sobjectly.config.ts or sobjectly.config.json)\n -e, --env-file <path> Load environment variables from a .env file first\n --check Don't write; exit with 1 when the generated file is out of date\n (formatting-only differences don't count)\n --stdout Print the generated source instead of writing it\n\nOptions for init (skip the matching questions; useful in scripts):\n --api-version <v> Salesforce API version, e.g. v66.0\n --output <path> Generated types file, e.g. src/generated/sobjects.ts\n --sobjects <list> Comma-separated sObject API names\n --auth <type> clientCredentials | sfCli | accessToken | jwtBearer\n --target-org <alias> Salesforce CLI org alias (with --auth sfCli)\n --picklists <mode> union | string\n --format <format> ts | json\n -y, --yes Use the suggested answer for every other question (needs --api-version)\n -f, --force Replace an existing config without asking\n\n -h, --help Show this help\n`;\n\nconst options = {\n\tconfig: { type: \"string\", short: \"c\" },\n\t\"env-file\": { type: \"string\", short: \"e\" },\n\t\"api-version\": { type: \"string\" },\n\toutput: { type: \"string\" },\n\tsobjects: { type: \"string\" },\n\tauth: { type: \"string\" },\n\tpicklists: { type: \"string\" },\n\tformat: { type: \"string\" },\n\tcheck: { type: \"boolean\" },\n\tstdout: { type: \"boolean\" },\n\t\"target-org\": { type: \"string\" },\n\tyes: { type: \"boolean\", short: \"y\" },\n\tforce: { type: \"boolean\", short: \"f\" },\n\thelp: { type: \"boolean\", short: \"h\" },\n} as const;\n\ninterface Values {\n\tconfig?: string;\n\t\"env-file\"?: string;\n\t\"api-version\"?: string;\n\toutput?: string;\n\tsobjects?: string;\n\tauth?: string;\n\tpicklists?: string;\n\tformat?: string;\n\tcheck?: boolean;\n\tstdout?: boolean;\n\t\"target-org\"?: string;\n\tyes?: boolean;\n\tforce?: boolean;\n\thelp?: boolean;\n}\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options });\n\tconst command = positionals[0] ?? \"generate\";\n\tif (values.help) {\n\t\tconsole.log(HELP);\n\t\treturn 0;\n\t}\n\tif (command === \"init\") {\n\t\treturn init(values);\n\t}\n\tif (command === \"generate\") {\n\t\treturn runGenerate(values);\n\t}\n\tconsole.error(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\treturn 1;\n}\n\nasync function init(values: Values): Promise<number> {\n\tconst preset = initPreset(values);\n\tconst prompter = readlinePrompter();\n\ttry {\n\t\tawait runInit({\n\t\t\tcwd: process.cwd(),\n\t\t\tprompter,\n\t\t\tlog: (message) => console.log(message),\n\t\t\tpreset,\n\t\t\tyes: values.yes,\n\t\t\tforce: values.force,\n\t\t});\n\t\treturn 0;\n\t} finally {\n\t\tprompter.close();\n\t}\n}\n\nfunction initPreset(values: Values): Partial<InitAnswers> {\n\tconst preset: Partial<InitAnswers> = {};\n\tif (values[\"api-version\"] !== undefined) {\n\t\tconst apiVersion = normalizeApiVersion(values[\"api-version\"]);\n\t\tif (!apiVersion) {\n\t\t\tthrow new Error(`Invalid --api-version \"${values[\"api-version\"]}\". Expected a value like v66.0.`);\n\t\t}\n\t\tpreset.apiVersion = apiVersion;\n\t}\n\tif (values.output !== undefined) {\n\t\tpreset.output = values.output;\n\t}\n\tif (values.sobjects !== undefined) {\n\t\tpreset.sobjects = parseSObjects(values.sobjects);\n\t}\n\tconst auth = oneOf(\"--auth\", values.auth, [\"clientCredentials\", \"sfCli\", \"accessToken\", \"jwtBearer\"] as const);\n\tif (values[\"target-org\"] !== undefined) {\n\t\tpreset.targetOrg = values[\"target-org\"];\n\t}\n\tconst picklists = oneOf(\"--picklists\", values.picklists, [\"union\", \"string\"] as const);\n\tconst format = oneOf(\"--format\", values.format, [\"ts\", \"json\"] as const);\n\treturn { ...preset, ...(auth && { auth }), ...(picklists && { picklists }), ...(format && { format }) };\n}\n\nfunction oneOf<T extends string>(flag: string, value: string | undefined, allowed: readonly T[]): T | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst match = allowed.find((item) => item === value);\n\tif (!match) {\n\t\tthrow new Error(`Invalid ${flag} \"${value}\". Expected one of: ${allowed.join(\", \")}.`);\n\t}\n\treturn match;\n}\n\nasync function runGenerate(values: Values): Promise<number> {\n\tif (values[\"env-file\"]) {\n\t\tconst envFile = resolve(values[\"env-file\"]);\n\t\tif (!existsSync(envFile)) {\n\t\t\tconsole.error(`Env file not found: ${envFile}`);\n\t\t\treturn 1;\n\t\t}\n\t\tprocess.loadEnvFile(envFile);\n\t}\n\tconst found = findConfigFiles();\n\tif (!values.config && found.length > 1) {\n\t\tconsole.warn(`warning: found ${found.join(\" and \")}; using ${found[0]}. Remove the other one.`);\n\t}\n\tconst configPath = values.config ? resolve(values.config) : found[0];\n\tif (!configPath) {\n\t\tconsole.error('No sobjectly config file found. Run \"npx sobjectly init\" to create one, or pass --config.');\n\t\treturn 1;\n\t}\n\tconst { config, directory } = await loadConfig(configPath);\n\t// With --stdout the source goes to stdout, so progress goes to stderr.\n\tconst log = values.stdout\n\t\t? (message: string): void => console.error(message)\n\t\t: (message: string): void => console.log(message);\n\tconst logger = { info: log, warn: (message: string): void => console.warn(`warning: ${message}`) };\n\tif (values.check) {\n\t\treturn reportCheck(await checkGenerated(config, { cwd: directory, logger }));\n\t}\n\tconst result = await generate(config, { cwd: directory, logger, write: !values.stdout });\n\tif (values.stdout) {\n\t\tprocess.stdout.write(result.source);\n\t}\n\tif (result.skipped.length > 0) {\n\t\tconsole.warn(`Skipped ${result.skipped.length} sObject(s): ${result.skipped.map((item) => item.name).join(\", \")}`);\n\t}\n\treturn 0;\n}\n\nfunction reportCheck(result: Awaited<ReturnType<typeof checkGenerated>>): number {\n\tif (result.upToDate) {\n\t\tconsole.log(`${result.outputPath} is up to date.`);\n\t\treturn 0;\n\t}\n\tif (result.reason === \"missing\") {\n\t\tconsole.error(`${result.outputPath} does not exist. Run \"sobjectly generate\".`);\n\t\treturn 1;\n\t}\n\tconst details = [\n\t\tresult.added.length > 0 ? `added: ${result.added.join(\", \")}` : \"\",\n\t\tresult.removed.length > 0 ? `removed: ${result.removed.join(\", \")}` : \"\",\n\t\tresult.changed.length > 0 ? `changed: ${result.changed.join(\", \")}` : \"\",\n\t].filter((detail) => detail.length > 0);\n\tconsole.error(\n\t\t`${result.outputPath} is out of date${details.length > 0 ? ` (${details.join(\"; \")})` : \"\"}. Run \"sobjectly generate\".`,\n\t);\n\treturn 1;\n}\n\nmain(process.argv.slice(2))\n\t.then((code) => {\n\t\tprocess.exitCode = code;\n\t})\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : error);\n\t\tprocess.exitCode = 1;\n\t});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.cjs","names":["parseArgs","readlinePrompter","runInit","normalizeApiVersion","parseSObjects","PICKLIST_MODES","resolve","existsSync","findConfigFiles","loadConfig","checkGenerated","generate"],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/* oxlint-disable no-console */\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\n\nimport { normalizeApiVersion } from \"./api-version\";\nimport { checkGenerated, findConfigFiles, generate, loadConfig } from \"./codegen/index\";\nimport { type InitAnswers, parseSObjects, runInit } from \"./codegen/init\";\nimport { readlinePrompter } from \"./codegen/prompter\";\nimport { PICKLIST_MODES } from \"./codegen/validate-config\";\n\nconst HELP = `Usage: sobjectly <command> [options]\n\nCommands:\n init Create a sobjectly.config file by answering a few questions\n generate Generate TypeScript types for Salesforce sObjects (default)\n\nOptions for generate:\n -c, --config <path> Config file (default: sobjectly.config.ts or sobjectly.config.json)\n -e, --env-file <path> Load environment variables from a .env file first\n --check Don't write; exit with 1 when the generated file is out of date\n (formatting-only differences don't count)\n --stdout Print the generated source instead of writing it\n\nOptions for init (skip the matching questions; useful in scripts):\n --api-version <v> Salesforce API version, e.g. v66.0\n --output <path> Generated types file, e.g. src/generated/sobjects.ts\n --sobjects <list> Comma-separated sObject API names\n --auth <type> clientCredentials | sfCli | accessToken | jwtBearer\n --target-org <alias> Salesforce CLI org alias (with --auth sfCli)\n --picklists <mode> union | string | const | enum\n --format <format> ts | json\n -y, --yes Use the suggested answer for every other question (needs --api-version)\n -f, --force Replace an existing config without asking\n\n -h, --help Show this help\n`;\n\nconst options = {\n\tconfig: { type: \"string\", short: \"c\" },\n\t\"env-file\": { type: \"string\", short: \"e\" },\n\t\"api-version\": { type: \"string\" },\n\toutput: { type: \"string\" },\n\tsobjects: { type: \"string\" },\n\tauth: { type: \"string\" },\n\tpicklists: { type: \"string\" },\n\tformat: { type: \"string\" },\n\tcheck: { type: \"boolean\" },\n\tstdout: { type: \"boolean\" },\n\t\"target-org\": { type: \"string\" },\n\tyes: { type: \"boolean\", short: \"y\" },\n\tforce: { type: \"boolean\", short: \"f\" },\n\thelp: { type: \"boolean\", short: \"h\" },\n} as const;\n\ninterface Values {\n\tconfig?: string;\n\t\"env-file\"?: string;\n\t\"api-version\"?: string;\n\toutput?: string;\n\tsobjects?: string;\n\tauth?: string;\n\tpicklists?: string;\n\tformat?: string;\n\tcheck?: boolean;\n\tstdout?: boolean;\n\t\"target-org\"?: string;\n\tyes?: boolean;\n\tforce?: boolean;\n\thelp?: boolean;\n}\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options });\n\tconst command = positionals[0] ?? \"generate\";\n\tif (values.help) {\n\t\tconsole.log(HELP);\n\t\treturn 0;\n\t}\n\tif (command === \"init\") {\n\t\treturn init(values);\n\t}\n\tif (command === \"generate\") {\n\t\treturn runGenerate(values);\n\t}\n\tconsole.error(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\treturn 1;\n}\n\nasync function init(values: Values): Promise<number> {\n\tconst preset = initPreset(values);\n\tconst prompter = readlinePrompter();\n\ttry {\n\t\tawait runInit({\n\t\t\tcwd: process.cwd(),\n\t\t\tprompter,\n\t\t\tlog: (message) => console.log(message),\n\t\t\tpreset,\n\t\t\tyes: values.yes,\n\t\t\tforce: values.force,\n\t\t});\n\t\treturn 0;\n\t} finally {\n\t\tprompter.close();\n\t}\n}\n\nfunction initPreset(values: Values): Partial<InitAnswers> {\n\tconst preset: Partial<InitAnswers> = {};\n\tif (values[\"api-version\"] !== undefined) {\n\t\tconst apiVersion = normalizeApiVersion(values[\"api-version\"]);\n\t\tif (!apiVersion) {\n\t\t\tthrow new Error(`Invalid --api-version \"${values[\"api-version\"]}\". Expected a value like v66.0.`);\n\t\t}\n\t\tpreset.apiVersion = apiVersion;\n\t}\n\tif (values.output !== undefined) {\n\t\tpreset.output = values.output;\n\t}\n\tif (values.sobjects !== undefined) {\n\t\tpreset.sobjects = parseSObjects(values.sobjects);\n\t}\n\tconst auth = oneOf(\"--auth\", values.auth, [\"clientCredentials\", \"sfCli\", \"accessToken\", \"jwtBearer\"] as const);\n\tif (values[\"target-org\"] !== undefined) {\n\t\tpreset.targetOrg = values[\"target-org\"];\n\t}\n\tconst picklists = oneOf(\"--picklists\", values.picklists, PICKLIST_MODES);\n\tconst format = oneOf(\"--format\", values.format, [\"ts\", \"json\"] as const);\n\treturn { ...preset, ...(auth && { auth }), ...(picklists && { picklists }), ...(format && { format }) };\n}\n\nfunction oneOf<T extends string>(flag: string, value: string | undefined, allowed: readonly T[]): T | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst match = allowed.find((item) => item === value);\n\tif (!match) {\n\t\tthrow new Error(`Invalid ${flag} \"${value}\". Expected one of: ${allowed.join(\", \")}.`);\n\t}\n\treturn match;\n}\n\nasync function runGenerate(values: Values): Promise<number> {\n\tif (values[\"env-file\"]) {\n\t\tconst envFile = resolve(values[\"env-file\"]);\n\t\tif (!existsSync(envFile)) {\n\t\t\tconsole.error(`Env file not found: ${envFile}`);\n\t\t\treturn 1;\n\t\t}\n\t\tprocess.loadEnvFile(envFile);\n\t}\n\tconst found = findConfigFiles();\n\tif (!values.config && found.length > 1) {\n\t\tconsole.warn(`warning: found ${found.join(\" and \")}; using ${found[0]}. Remove the other one.`);\n\t}\n\tconst configPath = values.config ? resolve(values.config) : found[0];\n\tif (!configPath) {\n\t\tconsole.error('No sobjectly config file found. Run \"npx sobjectly init\" to create one, or pass --config.');\n\t\treturn 1;\n\t}\n\tconst { config, directory } = await loadConfig(configPath);\n\t// With --stdout the source goes to stdout, so progress goes to stderr.\n\tconst log = values.stdout\n\t\t? (message: string): void => console.error(message)\n\t\t: (message: string): void => console.log(message);\n\tconst logger = { info: log, warn: (message: string): void => console.warn(`warning: ${message}`) };\n\tif (values.check) {\n\t\treturn reportCheck(await checkGenerated(config, { cwd: directory, logger }));\n\t}\n\tconst result = await generate(config, { cwd: directory, logger, write: !values.stdout });\n\tif (values.stdout) {\n\t\tprocess.stdout.write(result.source);\n\t}\n\tif (result.skipped.length > 0) {\n\t\tconsole.warn(`Skipped ${result.skipped.length} sObject(s): ${result.skipped.map((item) => item.name).join(\", \")}`);\n\t}\n\treturn 0;\n}\n\nfunction reportCheck(result: Awaited<ReturnType<typeof checkGenerated>>): number {\n\tif (result.upToDate) {\n\t\tconsole.log(`${result.outputPath} is up to date.`);\n\t\treturn 0;\n\t}\n\tif (result.reason === \"missing\") {\n\t\tconsole.error(`${result.outputPath} does not exist. Run \"sobjectly generate\".`);\n\t\treturn 1;\n\t}\n\tconst details = [\n\t\tresult.added.length > 0 ? `added: ${result.added.join(\", \")}` : \"\",\n\t\tresult.removed.length > 0 ? `removed: ${result.removed.join(\", \")}` : \"\",\n\t\tresult.changed.length > 0 ? `changed: ${result.changed.join(\", \")}` : \"\",\n\t].filter((detail) => detail.length > 0);\n\tconsole.error(\n\t\t`${result.outputPath} is out of date${details.length > 0 ? ` (${details.join(\"; \")})` : \"\"}. Run \"sobjectly generate\".`,\n\t);\n\treturn 1;\n}\n\nmain(process.argv.slice(2))\n\t.then((code) => {\n\t\tprocess.exitCode = code;\n\t})\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : error);\n\t\tprocess.exitCode = 1;\n\t});\n"],"mappings":"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"}
|
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Lt as __commonJSMin, Mt as init_api_version, Pt as normalizeApiVersion } from "./sf-cli-
|
|
3
|
-
import { a as init_prompter, c as init_init, d as runInit, g as loadConfig, l as parseSObjects, m as findConfigFiles, n as generate, o as readlinePrompter, r as init_codegen, t as checkGenerated } from "./codegen-
|
|
2
|
+
import { Lt as __commonJSMin, Mt as init_api_version, Pt as normalizeApiVersion } from "./sf-cli-_Ua-M_Zi.mjs";
|
|
3
|
+
import { C as init_validate_config, S as PICKLIST_MODES, a as init_prompter, c as init_init, d as runInit, g as loadConfig, l as parseSObjects, m as findConfigFiles, n as generate, o as readlinePrompter, r as init_codegen, t as checkGenerated } from "./codegen-C6MEYiWo.mjs";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
import { parseArgs } from "node:util";
|
|
@@ -10,6 +10,7 @@ var require_cli = /* @__PURE__ */ __commonJSMin((() => {
|
|
|
10
10
|
init_codegen();
|
|
11
11
|
init_init();
|
|
12
12
|
init_prompter();
|
|
13
|
+
init_validate_config();
|
|
13
14
|
const HELP = `Usage: sobjectly <command> [options]
|
|
14
15
|
|
|
15
16
|
Commands:
|
|
@@ -29,7 +30,7 @@ Options for init (skip the matching questions; useful in scripts):
|
|
|
29
30
|
--sobjects <list> Comma-separated sObject API names
|
|
30
31
|
--auth <type> clientCredentials | sfCli | accessToken | jwtBearer
|
|
31
32
|
--target-org <alias> Salesforce CLI org alias (with --auth sfCli)
|
|
32
|
-
--picklists <mode> union | string
|
|
33
|
+
--picklists <mode> union | string | const | enum
|
|
33
34
|
--format <format> ts | json
|
|
34
35
|
-y, --yes Use the suggested answer for every other question (needs --api-version)
|
|
35
36
|
-f, --force Replace an existing config without asking
|
|
@@ -116,7 +117,7 @@ Options for init (skip the matching questions; useful in scripts):
|
|
|
116
117
|
"jwtBearer"
|
|
117
118
|
]);
|
|
118
119
|
if (values["target-org"] !== void 0) preset.targetOrg = values["target-org"];
|
|
119
|
-
const picklists = oneOf("--picklists", values.picklists,
|
|
120
|
+
const picklists = oneOf("--picklists", values.picklists, PICKLIST_MODES);
|
|
120
121
|
const format = oneOf("--format", values.format, ["ts", "json"]);
|
|
121
122
|
return {
|
|
122
123
|
...preset,
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/* oxlint-disable no-console */\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\n\nimport { normalizeApiVersion } from \"./api-version\";\nimport { checkGenerated, findConfigFiles, generate, loadConfig } from \"./codegen/index\";\nimport { type InitAnswers, parseSObjects, runInit } from \"./codegen/init\";\nimport { readlinePrompter } from \"./codegen/prompter\";\n\nconst HELP = `Usage: sobjectly <command> [options]\n\nCommands:\n init Create a sobjectly.config file by answering a few questions\n generate Generate TypeScript types for Salesforce sObjects (default)\n\nOptions for generate:\n -c, --config <path> Config file (default: sobjectly.config.ts or sobjectly.config.json)\n -e, --env-file <path> Load environment variables from a .env file first\n --check Don't write; exit with 1 when the generated file is out of date\n (formatting-only differences don't count)\n --stdout Print the generated source instead of writing it\n\nOptions for init (skip the matching questions; useful in scripts):\n --api-version <v> Salesforce API version, e.g. v66.0\n --output <path> Generated types file, e.g. src/generated/sobjects.ts\n --sobjects <list> Comma-separated sObject API names\n --auth <type> clientCredentials | sfCli | accessToken | jwtBearer\n --target-org <alias> Salesforce CLI org alias (with --auth sfCli)\n --picklists <mode> union | string\n --format <format> ts | json\n -y, --yes Use the suggested answer for every other question (needs --api-version)\n -f, --force Replace an existing config without asking\n\n -h, --help Show this help\n`;\n\nconst options = {\n\tconfig: { type: \"string\", short: \"c\" },\n\t\"env-file\": { type: \"string\", short: \"e\" },\n\t\"api-version\": { type: \"string\" },\n\toutput: { type: \"string\" },\n\tsobjects: { type: \"string\" },\n\tauth: { type: \"string\" },\n\tpicklists: { type: \"string\" },\n\tformat: { type: \"string\" },\n\tcheck: { type: \"boolean\" },\n\tstdout: { type: \"boolean\" },\n\t\"target-org\": { type: \"string\" },\n\tyes: { type: \"boolean\", short: \"y\" },\n\tforce: { type: \"boolean\", short: \"f\" },\n\thelp: { type: \"boolean\", short: \"h\" },\n} as const;\n\ninterface Values {\n\tconfig?: string;\n\t\"env-file\"?: string;\n\t\"api-version\"?: string;\n\toutput?: string;\n\tsobjects?: string;\n\tauth?: string;\n\tpicklists?: string;\n\tformat?: string;\n\tcheck?: boolean;\n\tstdout?: boolean;\n\t\"target-org\"?: string;\n\tyes?: boolean;\n\tforce?: boolean;\n\thelp?: boolean;\n}\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options });\n\tconst command = positionals[0] ?? \"generate\";\n\tif (values.help) {\n\t\tconsole.log(HELP);\n\t\treturn 0;\n\t}\n\tif (command === \"init\") {\n\t\treturn init(values);\n\t}\n\tif (command === \"generate\") {\n\t\treturn runGenerate(values);\n\t}\n\tconsole.error(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\treturn 1;\n}\n\nasync function init(values: Values): Promise<number> {\n\tconst preset = initPreset(values);\n\tconst prompter = readlinePrompter();\n\ttry {\n\t\tawait runInit({\n\t\t\tcwd: process.cwd(),\n\t\t\tprompter,\n\t\t\tlog: (message) => console.log(message),\n\t\t\tpreset,\n\t\t\tyes: values.yes,\n\t\t\tforce: values.force,\n\t\t});\n\t\treturn 0;\n\t} finally {\n\t\tprompter.close();\n\t}\n}\n\nfunction initPreset(values: Values): Partial<InitAnswers> {\n\tconst preset: Partial<InitAnswers> = {};\n\tif (values[\"api-version\"] !== undefined) {\n\t\tconst apiVersion = normalizeApiVersion(values[\"api-version\"]);\n\t\tif (!apiVersion) {\n\t\t\tthrow new Error(`Invalid --api-version \"${values[\"api-version\"]}\". Expected a value like v66.0.`);\n\t\t}\n\t\tpreset.apiVersion = apiVersion;\n\t}\n\tif (values.output !== undefined) {\n\t\tpreset.output = values.output;\n\t}\n\tif (values.sobjects !== undefined) {\n\t\tpreset.sobjects = parseSObjects(values.sobjects);\n\t}\n\tconst auth = oneOf(\"--auth\", values.auth, [\"clientCredentials\", \"sfCli\", \"accessToken\", \"jwtBearer\"] as const);\n\tif (values[\"target-org\"] !== undefined) {\n\t\tpreset.targetOrg = values[\"target-org\"];\n\t}\n\tconst picklists = oneOf(\"--picklists\", values.picklists, [\"union\", \"string\"] as const);\n\tconst format = oneOf(\"--format\", values.format, [\"ts\", \"json\"] as const);\n\treturn { ...preset, ...(auth && { auth }), ...(picklists && { picklists }), ...(format && { format }) };\n}\n\nfunction oneOf<T extends string>(flag: string, value: string | undefined, allowed: readonly T[]): T | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst match = allowed.find((item) => item === value);\n\tif (!match) {\n\t\tthrow new Error(`Invalid ${flag} \"${value}\". Expected one of: ${allowed.join(\", \")}.`);\n\t}\n\treturn match;\n}\n\nasync function runGenerate(values: Values): Promise<number> {\n\tif (values[\"env-file\"]) {\n\t\tconst envFile = resolve(values[\"env-file\"]);\n\t\tif (!existsSync(envFile)) {\n\t\t\tconsole.error(`Env file not found: ${envFile}`);\n\t\t\treturn 1;\n\t\t}\n\t\tprocess.loadEnvFile(envFile);\n\t}\n\tconst found = findConfigFiles();\n\tif (!values.config && found.length > 1) {\n\t\tconsole.warn(`warning: found ${found.join(\" and \")}; using ${found[0]}. Remove the other one.`);\n\t}\n\tconst configPath = values.config ? resolve(values.config) : found[0];\n\tif (!configPath) {\n\t\tconsole.error('No sobjectly config file found. Run \"npx sobjectly init\" to create one, or pass --config.');\n\t\treturn 1;\n\t}\n\tconst { config, directory } = await loadConfig(configPath);\n\t// With --stdout the source goes to stdout, so progress goes to stderr.\n\tconst log = values.stdout\n\t\t? (message: string): void => console.error(message)\n\t\t: (message: string): void => console.log(message);\n\tconst logger = { info: log, warn: (message: string): void => console.warn(`warning: ${message}`) };\n\tif (values.check) {\n\t\treturn reportCheck(await checkGenerated(config, { cwd: directory, logger }));\n\t}\n\tconst result = await generate(config, { cwd: directory, logger, write: !values.stdout });\n\tif (values.stdout) {\n\t\tprocess.stdout.write(result.source);\n\t}\n\tif (result.skipped.length > 0) {\n\t\tconsole.warn(`Skipped ${result.skipped.length} sObject(s): ${result.skipped.map((item) => item.name).join(\", \")}`);\n\t}\n\treturn 0;\n}\n\nfunction reportCheck(result: Awaited<ReturnType<typeof checkGenerated>>): number {\n\tif (result.upToDate) {\n\t\tconsole.log(`${result.outputPath} is up to date.`);\n\t\treturn 0;\n\t}\n\tif (result.reason === \"missing\") {\n\t\tconsole.error(`${result.outputPath} does not exist. Run \"sobjectly generate\".`);\n\t\treturn 1;\n\t}\n\tconst details = [\n\t\tresult.added.length > 0 ? `added: ${result.added.join(\", \")}` : \"\",\n\t\tresult.removed.length > 0 ? `removed: ${result.removed.join(\", \")}` : \"\",\n\t\tresult.changed.length > 0 ? `changed: ${result.changed.join(\", \")}` : \"\",\n\t].filter((detail) => detail.length > 0);\n\tconsole.error(\n\t\t`${result.outputPath} is out of date${details.length > 0 ? ` (${details.join(\"; \")})` : \"\"}. Run \"sobjectly generate\".`,\n\t);\n\treturn 1;\n}\n\nmain(process.argv.slice(2))\n\t.then((code) => {\n\t\tprocess.exitCode = code;\n\t})\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : error);\n\t\tprocess.exitCode = 1;\n\t});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/* oxlint-disable no-console */\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\n\nimport { normalizeApiVersion } from \"./api-version\";\nimport { checkGenerated, findConfigFiles, generate, loadConfig } from \"./codegen/index\";\nimport { type InitAnswers, parseSObjects, runInit } from \"./codegen/init\";\nimport { readlinePrompter } from \"./codegen/prompter\";\nimport { PICKLIST_MODES } from \"./codegen/validate-config\";\n\nconst HELP = `Usage: sobjectly <command> [options]\n\nCommands:\n init Create a sobjectly.config file by answering a few questions\n generate Generate TypeScript types for Salesforce sObjects (default)\n\nOptions for generate:\n -c, --config <path> Config file (default: sobjectly.config.ts or sobjectly.config.json)\n -e, --env-file <path> Load environment variables from a .env file first\n --check Don't write; exit with 1 when the generated file is out of date\n (formatting-only differences don't count)\n --stdout Print the generated source instead of writing it\n\nOptions for init (skip the matching questions; useful in scripts):\n --api-version <v> Salesforce API version, e.g. v66.0\n --output <path> Generated types file, e.g. src/generated/sobjects.ts\n --sobjects <list> Comma-separated sObject API names\n --auth <type> clientCredentials | sfCli | accessToken | jwtBearer\n --target-org <alias> Salesforce CLI org alias (with --auth sfCli)\n --picklists <mode> union | string | const | enum\n --format <format> ts | json\n -y, --yes Use the suggested answer for every other question (needs --api-version)\n -f, --force Replace an existing config without asking\n\n -h, --help Show this help\n`;\n\nconst options = {\n\tconfig: { type: \"string\", short: \"c\" },\n\t\"env-file\": { type: \"string\", short: \"e\" },\n\t\"api-version\": { type: \"string\" },\n\toutput: { type: \"string\" },\n\tsobjects: { type: \"string\" },\n\tauth: { type: \"string\" },\n\tpicklists: { type: \"string\" },\n\tformat: { type: \"string\" },\n\tcheck: { type: \"boolean\" },\n\tstdout: { type: \"boolean\" },\n\t\"target-org\": { type: \"string\" },\n\tyes: { type: \"boolean\", short: \"y\" },\n\tforce: { type: \"boolean\", short: \"f\" },\n\thelp: { type: \"boolean\", short: \"h\" },\n} as const;\n\ninterface Values {\n\tconfig?: string;\n\t\"env-file\"?: string;\n\t\"api-version\"?: string;\n\toutput?: string;\n\tsobjects?: string;\n\tauth?: string;\n\tpicklists?: string;\n\tformat?: string;\n\tcheck?: boolean;\n\tstdout?: boolean;\n\t\"target-org\"?: string;\n\tyes?: boolean;\n\tforce?: boolean;\n\thelp?: boolean;\n}\n\nasync function main(argv: string[]): Promise<number> {\n\tconst { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options });\n\tconst command = positionals[0] ?? \"generate\";\n\tif (values.help) {\n\t\tconsole.log(HELP);\n\t\treturn 0;\n\t}\n\tif (command === \"init\") {\n\t\treturn init(values);\n\t}\n\tif (command === \"generate\") {\n\t\treturn runGenerate(values);\n\t}\n\tconsole.error(`Unknown command \"${command}\".\\n\\n${HELP}`);\n\treturn 1;\n}\n\nasync function init(values: Values): Promise<number> {\n\tconst preset = initPreset(values);\n\tconst prompter = readlinePrompter();\n\ttry {\n\t\tawait runInit({\n\t\t\tcwd: process.cwd(),\n\t\t\tprompter,\n\t\t\tlog: (message) => console.log(message),\n\t\t\tpreset,\n\t\t\tyes: values.yes,\n\t\t\tforce: values.force,\n\t\t});\n\t\treturn 0;\n\t} finally {\n\t\tprompter.close();\n\t}\n}\n\nfunction initPreset(values: Values): Partial<InitAnswers> {\n\tconst preset: Partial<InitAnswers> = {};\n\tif (values[\"api-version\"] !== undefined) {\n\t\tconst apiVersion = normalizeApiVersion(values[\"api-version\"]);\n\t\tif (!apiVersion) {\n\t\t\tthrow new Error(`Invalid --api-version \"${values[\"api-version\"]}\". Expected a value like v66.0.`);\n\t\t}\n\t\tpreset.apiVersion = apiVersion;\n\t}\n\tif (values.output !== undefined) {\n\t\tpreset.output = values.output;\n\t}\n\tif (values.sobjects !== undefined) {\n\t\tpreset.sobjects = parseSObjects(values.sobjects);\n\t}\n\tconst auth = oneOf(\"--auth\", values.auth, [\"clientCredentials\", \"sfCli\", \"accessToken\", \"jwtBearer\"] as const);\n\tif (values[\"target-org\"] !== undefined) {\n\t\tpreset.targetOrg = values[\"target-org\"];\n\t}\n\tconst picklists = oneOf(\"--picklists\", values.picklists, PICKLIST_MODES);\n\tconst format = oneOf(\"--format\", values.format, [\"ts\", \"json\"] as const);\n\treturn { ...preset, ...(auth && { auth }), ...(picklists && { picklists }), ...(format && { format }) };\n}\n\nfunction oneOf<T extends string>(flag: string, value: string | undefined, allowed: readonly T[]): T | undefined {\n\tif (value === undefined) {\n\t\treturn undefined;\n\t}\n\tconst match = allowed.find((item) => item === value);\n\tif (!match) {\n\t\tthrow new Error(`Invalid ${flag} \"${value}\". Expected one of: ${allowed.join(\", \")}.`);\n\t}\n\treturn match;\n}\n\nasync function runGenerate(values: Values): Promise<number> {\n\tif (values[\"env-file\"]) {\n\t\tconst envFile = resolve(values[\"env-file\"]);\n\t\tif (!existsSync(envFile)) {\n\t\t\tconsole.error(`Env file not found: ${envFile}`);\n\t\t\treturn 1;\n\t\t}\n\t\tprocess.loadEnvFile(envFile);\n\t}\n\tconst found = findConfigFiles();\n\tif (!values.config && found.length > 1) {\n\t\tconsole.warn(`warning: found ${found.join(\" and \")}; using ${found[0]}. Remove the other one.`);\n\t}\n\tconst configPath = values.config ? resolve(values.config) : found[0];\n\tif (!configPath) {\n\t\tconsole.error('No sobjectly config file found. Run \"npx sobjectly init\" to create one, or pass --config.');\n\t\treturn 1;\n\t}\n\tconst { config, directory } = await loadConfig(configPath);\n\t// With --stdout the source goes to stdout, so progress goes to stderr.\n\tconst log = values.stdout\n\t\t? (message: string): void => console.error(message)\n\t\t: (message: string): void => console.log(message);\n\tconst logger = { info: log, warn: (message: string): void => console.warn(`warning: ${message}`) };\n\tif (values.check) {\n\t\treturn reportCheck(await checkGenerated(config, { cwd: directory, logger }));\n\t}\n\tconst result = await generate(config, { cwd: directory, logger, write: !values.stdout });\n\tif (values.stdout) {\n\t\tprocess.stdout.write(result.source);\n\t}\n\tif (result.skipped.length > 0) {\n\t\tconsole.warn(`Skipped ${result.skipped.length} sObject(s): ${result.skipped.map((item) => item.name).join(\", \")}`);\n\t}\n\treturn 0;\n}\n\nfunction reportCheck(result: Awaited<ReturnType<typeof checkGenerated>>): number {\n\tif (result.upToDate) {\n\t\tconsole.log(`${result.outputPath} is up to date.`);\n\t\treturn 0;\n\t}\n\tif (result.reason === \"missing\") {\n\t\tconsole.error(`${result.outputPath} does not exist. Run \"sobjectly generate\".`);\n\t\treturn 1;\n\t}\n\tconst details = [\n\t\tresult.added.length > 0 ? `added: ${result.added.join(\", \")}` : \"\",\n\t\tresult.removed.length > 0 ? `removed: ${result.removed.join(\", \")}` : \"\",\n\t\tresult.changed.length > 0 ? `changed: ${result.changed.join(\", \")}` : \"\",\n\t].filter((detail) => detail.length > 0);\n\tconsole.error(\n\t\t`${result.outputPath} is out of date${details.length > 0 ? ` (${details.join(\"; \")})` : \"\"}. Run \"sobjectly generate\".`,\n\t);\n\treturn 1;\n}\n\nmain(process.argv.slice(2))\n\t.then((code) => {\n\t\tprocess.exitCode = code;\n\t})\n\t.catch((error: unknown) => {\n\t\tconsole.error(error instanceof Error ? error.message : error);\n\t\tprocess.exitCode = 1;\n\t});\n"],"mappings":"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"}
|
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
const require_sf_cli = require("./sf-cli-
|
|
1
|
+
const require_sf_cli = require("./sf-cli-R6LHwqoo.cjs");
|
|
2
2
|
let node_crypto = require("node:crypto");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
let node_fs_promises = require("node:fs/promises");
|
|
5
5
|
let node_path = require("node:path");
|
|
6
6
|
let jiti = require("jiti");
|
|
7
7
|
let node_readline = require("node:readline");
|
|
8
|
+
//#region src/codegen/emit.ts
|
|
9
|
+
/** Helpers shared by the modules that emit generated source. */
|
|
10
|
+
const IDENTIFIER$1 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
11
|
+
/** Fields sorted by name, `Id` first, so the output is deterministic. */
|
|
12
|
+
function sortedFields(describe) {
|
|
13
|
+
return [...describe.fields].sort((a, b) => a.name === "Id" ? -1 : b.name === "Id" ? 1 : compare(a.name, b.name));
|
|
14
|
+
}
|
|
15
|
+
/** An object key: the bare name when it is an identifier, otherwise a quoted string. */
|
|
16
|
+
function propertyKey(name) {
|
|
17
|
+
return IDENTIFIER$1.test(name) ? name : JSON.stringify(name);
|
|
18
|
+
}
|
|
19
|
+
function escapeComment(value) {
|
|
20
|
+
return String(value ?? "").replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
21
|
+
}
|
|
22
|
+
function compare(a, b) {
|
|
23
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
8
26
|
//#region src/codegen/type-mapper.ts
|
|
9
27
|
const ADDRESS_TYPE = "SalesforceAddress";
|
|
10
28
|
const GEOLOCATION_TYPE = "SalesforceGeolocation";
|
|
@@ -39,17 +57,143 @@ const FIELD_TYPE_MAP = {
|
|
|
39
57
|
address: ADDRESS_TYPE,
|
|
40
58
|
location: GEOLOCATION_TYPE
|
|
41
59
|
};
|
|
42
|
-
/**
|
|
43
|
-
|
|
44
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Returns the TypeScript type for a field, including `| null` for nillable fields. With picklist
|
|
62
|
+
* mode `"const"` or `"enum"`, `typeName` is the field's named picklist type; it replaces the union.
|
|
63
|
+
*/
|
|
64
|
+
function mapFieldType(field, picklists = "union", typeName) {
|
|
65
|
+
const base = picklistType(field, picklists, typeName) ?? FIELD_TYPE_MAP[field.type] ?? "unknown";
|
|
45
66
|
return field.nillable && base !== "unknown" ? `${base} | null` : base;
|
|
46
67
|
}
|
|
47
|
-
function picklistType(field, picklists) {
|
|
48
|
-
if (picklists
|
|
49
|
-
const values =
|
|
68
|
+
function picklistType(field, picklists, typeName) {
|
|
69
|
+
if (picklists === "string" || field.type !== "picklist" && field.type !== "combobox") return;
|
|
70
|
+
const values = activePicklistValues(field);
|
|
50
71
|
if (values.length === 0) return;
|
|
51
|
-
const
|
|
52
|
-
return field.restrictedPicklist && field.type === "picklist" ?
|
|
72
|
+
const members = picklists !== "union" && typeName !== void 0 ? typeName : values.map((value) => JSON.stringify(value)).join(" | ");
|
|
73
|
+
return field.restrictedPicklist && field.type === "picklist" ? members : `${members} | (string & {})`;
|
|
74
|
+
}
|
|
75
|
+
/** The distinct active values of a picklist, multi-select picklist or combobox, in describe order. */
|
|
76
|
+
function activePicklistValues(field) {
|
|
77
|
+
if (field.type !== "picklist" && field.type !== "multipicklist" && field.type !== "combobox") return [];
|
|
78
|
+
return [...new Set((field.picklistValues ?? []).filter((entry) => entry.active).map((entry) => entry.value))];
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
//#region src/codegen/picklist-types.ts
|
|
82
|
+
function isNamedPicklistMode(mode) {
|
|
83
|
+
return mode === "const" || mode === "enum";
|
|
84
|
+
}
|
|
85
|
+
/** Appended to a picklist type name that is already taken, e.g. by the `CaseStatus` sObject. */
|
|
86
|
+
const CLASH_SUFFIX = "Picklist";
|
|
87
|
+
/**
|
|
88
|
+
* Names the type of every picklist with active values: sObject and field in PascalCase, e.g.
|
|
89
|
+
* `Case.Status` -> `CaseStatus` and `Case.Status__c` -> `CaseStatusCustom`. A name that is in
|
|
90
|
+
* `taken` (the sObjects and other names the file defines) or already used by another picklist gets
|
|
91
|
+
* the suffix `Picklist`; when that is taken too, this throws.
|
|
92
|
+
*/
|
|
93
|
+
function picklistTypeNames(describes, taken) {
|
|
94
|
+
const used = new Map([...taken].map((name) => [name, void 0]));
|
|
95
|
+
const result = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const describe of [...describes].sort((a, b) => compare(a.name, b.name))) {
|
|
97
|
+
const names = /* @__PURE__ */ new Map();
|
|
98
|
+
for (const field of sortedFields(describe).filter((item) => activePicklistValues(item).length > 0)) {
|
|
99
|
+
const base = `${pascalApiName(describe.name, "sobject")}${pascalApiName(field.name, "field")}`;
|
|
100
|
+
if (IDENTIFIER$1.test(base)) {
|
|
101
|
+
const picklist = `${describe.name}.${field.name}`;
|
|
102
|
+
const name = resolveName(base, picklist, used);
|
|
103
|
+
used.set(name, picklist);
|
|
104
|
+
names.set(field.name, name);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (names.size > 0) result.set(describe.name, names);
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
function resolveName(base, picklist, used) {
|
|
112
|
+
const name = used.has(base) ? `${base}${CLASH_SUFFIX}` : base;
|
|
113
|
+
if (used.has(name)) {
|
|
114
|
+
const owner = used.get(name);
|
|
115
|
+
const other = owner === void 0 ? "a type the generated file defines" : `the picklist type for ${owner}`;
|
|
116
|
+
throw new Error(`The picklist type "${name}" for ${picklist} clashes with ${other}; exclude one of the sObjects or use picklists: "union".`);
|
|
117
|
+
}
|
|
118
|
+
return name;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* An API name in PascalCase without underscores. A field's `__c` becomes `Custom`
|
|
122
|
+
* (`Lead_Source__c` -> `LeadSourceCustom`) and an sObject's is dropped (`My_Object__c` ->
|
|
123
|
+
* `MyObject`). Other suffixes are kept: `Foo__pc` -> `FooPc`, `Config__mdt` -> `ConfigMdt`.
|
|
124
|
+
*/
|
|
125
|
+
function pascalApiName(name, kind) {
|
|
126
|
+
const match = /^(.+?)__([a-z]+)$/.exec(name);
|
|
127
|
+
const body = match ? match[1] : name;
|
|
128
|
+
const suffix = match ? match[2] : "";
|
|
129
|
+
const suffixPart = suffix === "c" ? kind === "field" ? "Custom" : "" : capitalize(suffix);
|
|
130
|
+
return `${body.split("_").filter((part) => part.length > 0).map(capitalize).join("")}${suffixPart}`;
|
|
131
|
+
}
|
|
132
|
+
function capitalize(value) {
|
|
133
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The member names for a picklist's values, in the same order. A value that is an identifier is
|
|
137
|
+
* its own name; other values are sanitized (`"Closed Won"` -> `Closed_Won`, `"3rd Party"` ->
|
|
138
|
+
* `_3rd_Party`). When the sanitized name is empty or taken, the value itself is the (quoted) name.
|
|
139
|
+
*/
|
|
140
|
+
function picklistMemberKeys(values, mode) {
|
|
141
|
+
const used = /* @__PURE__ */ new Set();
|
|
142
|
+
const claim = (key) => {
|
|
143
|
+
used.add(key);
|
|
144
|
+
return key;
|
|
145
|
+
};
|
|
146
|
+
const usable = (key) => key.length > 0 && key !== "__proto__" && !used.has(key) && (mode === "const" || !isNumericName(key));
|
|
147
|
+
const own = values.map((value) => IDENTIFIER$1.test(value) && usable(value) ? claim(value) : void 0);
|
|
148
|
+
return values.map((value, index) => {
|
|
149
|
+
const ownKey = own[index];
|
|
150
|
+
if (ownKey !== void 0) return ownKey;
|
|
151
|
+
const sanitized = sanitizeKey(value);
|
|
152
|
+
if (usable(sanitized)) return claim(sanitized);
|
|
153
|
+
if (usable(value)) return claim(value);
|
|
154
|
+
let counter = 2;
|
|
155
|
+
while (!usable(`${sanitized || "_"}_${counter}`)) counter++;
|
|
156
|
+
return claim(`${sanitized || "_"}_${counter}`);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function sanitizeKey(value) {
|
|
160
|
+
const key = value.normalize("NFKD").replace(/\p{M}/gu, "").replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
|
|
161
|
+
return /^[0-9]/.test(key) ? `_${key}` : key;
|
|
162
|
+
}
|
|
163
|
+
/** Names TypeScript rejects as enum members because they are numeric, e.g. `"1"` or `"-1"`. */
|
|
164
|
+
function isNumericName(key) {
|
|
165
|
+
const number = Number(key);
|
|
166
|
+
return Number.isFinite(number) && String(number) === key;
|
|
167
|
+
}
|
|
168
|
+
/** The named type declarations for one sObject's picklists, in field order; `""` when there are none. */
|
|
169
|
+
function picklistDeclarations(describe, names, mode) {
|
|
170
|
+
if (!names) return "";
|
|
171
|
+
return sortedFields(describe).flatMap((field) => {
|
|
172
|
+
const name = names.get(field.name);
|
|
173
|
+
return name === void 0 ? [] : [declaration(describe.name, field, name, mode)];
|
|
174
|
+
}).join("\n\n");
|
|
175
|
+
}
|
|
176
|
+
function declaration(sobject, field, name, mode) {
|
|
177
|
+
const values = activePicklistValues(field);
|
|
178
|
+
const keys = picklistMemberKeys(values, mode);
|
|
179
|
+
const doc = `/** Active values of ${escapeComment(`${sobject}.${field.name}`)} (${escapeComment(field.type)}). */`;
|
|
180
|
+
if (mode === "enum") {
|
|
181
|
+
const members = values.map((value, index) => `\t${propertyKey(keys[index])} = ${JSON.stringify(value)},`);
|
|
182
|
+
return [
|
|
183
|
+
doc,
|
|
184
|
+
`export enum ${name} {`,
|
|
185
|
+
...members,
|
|
186
|
+
"}"
|
|
187
|
+
].join("\n");
|
|
188
|
+
}
|
|
189
|
+
const members = values.map((value, index) => `\t${propertyKey(keys[index])}: ${JSON.stringify(value)},`);
|
|
190
|
+
return [
|
|
191
|
+
doc,
|
|
192
|
+
`export const ${name} = {`,
|
|
193
|
+
...members,
|
|
194
|
+
"} as const;",
|
|
195
|
+
`export type ${name} = (typeof ${name})[keyof typeof ${name}];`
|
|
196
|
+
].join("\n");
|
|
53
197
|
}
|
|
54
198
|
//#endregion
|
|
55
199
|
//#region src/codegen/generator.ts
|
|
@@ -60,24 +204,28 @@ const FIELD_KINDS = /* @__PURE__ */ new Set([
|
|
|
60
204
|
"time",
|
|
61
205
|
"multipicklist"
|
|
62
206
|
]);
|
|
63
|
-
const IDENTIFIER$1 = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
64
207
|
/**
|
|
65
208
|
* Generates the TypeScript source for a set of sObject describes: a read interface, create
|
|
66
|
-
* and update input types per sObject, and the `SObjectRegistry` that ties them together.
|
|
209
|
+
* and update input types per sObject, and the `SObjectRegistry` that ties them together. With
|
|
210
|
+
* picklist mode `"const"` or `"enum"`, each picklist also gets a named type before its sObject.
|
|
67
211
|
* The output is deterministic: sObjects are sorted by name and fields by name (`Id` first).
|
|
68
212
|
*/
|
|
69
213
|
function generateSource(describes, options = {}) {
|
|
70
214
|
const sorted = [...describes].sort((a, b) => compare(a.name, b.name));
|
|
71
|
-
assertGeneratableNames(sorted);
|
|
215
|
+
const definedNames = assertGeneratableNames(sorted);
|
|
72
216
|
const names = new Set(sorted.map((describe) => describe.name));
|
|
217
|
+
const picklists = options.picklists ?? "union";
|
|
218
|
+
const picklistTypes = isNamedPicklistMode(picklists) ? picklistTypeNames(sorted, definedNames) : void 0;
|
|
73
219
|
const sections = [imports(sorted, options.importSource ?? "@cerios/salesforce-sobjectly")];
|
|
74
220
|
const objectHashes = [];
|
|
75
221
|
for (const describe of sorted) {
|
|
222
|
+
const typeNames = picklistTypes?.get(describe.name);
|
|
76
223
|
const objectSections = [
|
|
77
|
-
|
|
224
|
+
isNamedPicklistMode(picklists) ? picklistDeclarations(describe, typeNames, picklists) : "",
|
|
225
|
+
readInterface(describe, picklists, typeNames),
|
|
78
226
|
inputType(describe, "CreateInput", "createable", lookup(options.excludeCreateFields, describe.name)),
|
|
79
227
|
inputType(describe, "UpdateInput", "updateable", lookup(options.excludeUpdateFields, describe.name))
|
|
80
|
-
];
|
|
228
|
+
].filter((section) => section.length > 0);
|
|
81
229
|
sections.push(...objectSections);
|
|
82
230
|
const fingerprint = [
|
|
83
231
|
...objectSections,
|
|
@@ -104,7 +252,10 @@ const RESERVED_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
|
104
252
|
ADDRESS_TYPE,
|
|
105
253
|
GEOLOCATION_TYPE
|
|
106
254
|
]);
|
|
107
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Fails with a clear message for sObject names the generated TypeScript can't represent. Returns
|
|
257
|
+
* every name the file defines apart from picklist types, so those can avoid them.
|
|
258
|
+
*/
|
|
108
259
|
function assertGeneratableNames(describes) {
|
|
109
260
|
const seen = /* @__PURE__ */ new Map();
|
|
110
261
|
const generated = new Set(describes.flatMap((describe) => [`${describe.name}CreateInput`, `${describe.name}UpdateInput`]));
|
|
@@ -115,6 +266,11 @@ function assertGeneratableNames(describes) {
|
|
|
115
266
|
if (previous !== void 0) throw new Error(`sObjects "${previous}" and "${name}" differ only in case; list each sObject once.`);
|
|
116
267
|
seen.set(name.toLowerCase(), name);
|
|
117
268
|
}
|
|
269
|
+
return /* @__PURE__ */ new Set([
|
|
270
|
+
...RESERVED_TYPE_NAMES,
|
|
271
|
+
...generated,
|
|
272
|
+
...describes.map((describe) => describe.name)
|
|
273
|
+
]);
|
|
118
274
|
}
|
|
119
275
|
/** Looks up a per-sObject option case-insensitively (sObject names are case-insensitive in Salesforce). */
|
|
120
276
|
function lookup(map, name) {
|
|
@@ -162,12 +318,11 @@ function imports(describes, importSource) {
|
|
|
162
318
|
if (fields.some((field) => field.type === "location")) used.push(GEOLOCATION_TYPE);
|
|
163
319
|
return used.length > 0 ? `import type { ${used.join(", ")} } from ${JSON.stringify(importSource)};` : "";
|
|
164
320
|
}
|
|
165
|
-
function
|
|
166
|
-
return [...describe.fields].sort((a, b) => a.name === "Id" ? -1 : b.name === "Id" ? 1 : compare(a.name, b.name));
|
|
167
|
-
}
|
|
168
|
-
function readInterface(describe, picklists) {
|
|
321
|
+
function readInterface(describe, picklists, typeNames) {
|
|
169
322
|
const lines = sortedFields(describe).map((field) => {
|
|
170
|
-
|
|
323
|
+
const comment = `\t/** ${escapeComment(field.label)} (${escapeComment(field.type)}) */`;
|
|
324
|
+
const type = mapFieldType(field, picklists, typeNames?.get(field.name));
|
|
325
|
+
return `${comment}\n\t${propertyKey(field.name)}: ${type};`;
|
|
171
326
|
});
|
|
172
327
|
return `${describe.label ? `/** ${escapeComment(describe.label)} */\n` : ""}export interface ${describe.name} {\n${lines.join("\n")}\n}`;
|
|
173
328
|
}
|
|
@@ -254,10 +409,6 @@ function recordTypeConstants(describes) {
|
|
|
254
409
|
const entries = describes.map((describe) => [describe.name, recordTypeNames(describe)]).filter(([, names]) => names.length > 0).map(([name, names]) => `\t${name}: [${names.map((value) => JSON.stringify(value)).join(", ")}],`);
|
|
255
410
|
return ["/** Record type DeveloperNames per sObject. Resolve ids with `sf.sobject(name).recordTypeId(developerName)`. */", `export const RECORD_TYPES = {${entries.length > 0 ? `\n${entries.join("\n")}\n` : ""}} as const;`].join("\n");
|
|
256
411
|
}
|
|
257
|
-
function activePicklistValues(field) {
|
|
258
|
-
if (field.type !== "picklist" && field.type !== "multipicklist" && field.type !== "combobox") return [];
|
|
259
|
-
return [...new Set((field.picklistValues ?? []).filter((entry) => entry.active).map((entry) => entry.value))];
|
|
260
|
-
}
|
|
261
412
|
function unionOrNever(values) {
|
|
262
413
|
return values.length > 0 ? values.map((value) => JSON.stringify(value)).join(" | ") : "never";
|
|
263
414
|
}
|
|
@@ -280,15 +431,6 @@ function relationshipMap(entries) {
|
|
|
280
431
|
function keyUnion(names) {
|
|
281
432
|
return names.map((name) => JSON.stringify(name)).join(" | ");
|
|
282
433
|
}
|
|
283
|
-
function propertyKey(name) {
|
|
284
|
-
return IDENTIFIER$1.test(name) ? name : JSON.stringify(name);
|
|
285
|
-
}
|
|
286
|
-
function escapeComment(value) {
|
|
287
|
-
return String(value ?? "").replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
288
|
-
}
|
|
289
|
-
function compare(a, b) {
|
|
290
|
-
return a < b ? -1 : a > b ? 1 : 0;
|
|
291
|
-
}
|
|
292
434
|
//#endregion
|
|
293
435
|
//#region src/codegen/validate-config.ts
|
|
294
436
|
/** Thrown when a codegen config is invalid. Lists every problem found. */
|
|
@@ -319,7 +461,12 @@ const AUTH_OPTIONS = {
|
|
|
319
461
|
],
|
|
320
462
|
sfCli: ["targetOrg"]
|
|
321
463
|
};
|
|
322
|
-
const PICKLIST_MODES = [
|
|
464
|
+
const PICKLIST_MODES = [
|
|
465
|
+
"union",
|
|
466
|
+
"string",
|
|
467
|
+
"const",
|
|
468
|
+
"enum"
|
|
469
|
+
];
|
|
323
470
|
const IDENTIFIER = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
324
471
|
const VALIDATORS = {
|
|
325
472
|
$schema: (value, { problem }) => {
|
|
@@ -339,7 +486,7 @@ const VALIDATORS = {
|
|
|
339
486
|
excludeCreateFields: (value, context) => validateFieldMap("excludeCreateFields", value, context),
|
|
340
487
|
excludeUpdateFields: (value, context) => validateFieldMap("excludeUpdateFields", value, context),
|
|
341
488
|
picklists: (value, { problem }) => {
|
|
342
|
-
if (!PICKLIST_MODES.includes(value)) problem(`picklists: must be
|
|
489
|
+
if (!PICKLIST_MODES.includes(value)) problem(`picklists: must be one of ${PICKLIST_MODES.join(", ")}, got ${show(value)}.`);
|
|
343
490
|
},
|
|
344
491
|
constants: (value, { problem }) => {
|
|
345
492
|
if (typeof value !== "boolean") problem(`constants: must be true or false, got ${show(value)}.`);
|
|
@@ -544,13 +691,24 @@ const AUTH_CHOICES = [
|
|
|
544
691
|
label: "JWT bearer (certificate-based, runs as a user)"
|
|
545
692
|
}
|
|
546
693
|
];
|
|
547
|
-
const PICKLIST_CHOICES = [
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
694
|
+
const PICKLIST_CHOICES = [
|
|
695
|
+
{
|
|
696
|
+
value: "union",
|
|
697
|
+
label: "Union of values, e.g. \"New\" | \"Closed\" (type-safe)"
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
value: "string",
|
|
701
|
+
label: "Plain string"
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
value: "const",
|
|
705
|
+
label: "Union plus a named constant per picklist, e.g. CaseStatus.Closed"
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
value: "enum",
|
|
709
|
+
label: "TypeScript enum per picklist (restricted picklists only accept enum members)"
|
|
710
|
+
}
|
|
711
|
+
];
|
|
554
712
|
const FORMAT_CHOICES = [{
|
|
555
713
|
value: "ts",
|
|
556
714
|
label: "TypeScript (sobjectly.config.ts, type-checked with defineConfig)"
|
|
@@ -1115,6 +1273,12 @@ Object.defineProperty(exports, "FIELD_TYPE_MAP", {
|
|
|
1115
1273
|
return FIELD_TYPE_MAP;
|
|
1116
1274
|
}
|
|
1117
1275
|
});
|
|
1276
|
+
Object.defineProperty(exports, "PICKLIST_MODES", {
|
|
1277
|
+
enumerable: true,
|
|
1278
|
+
get: function() {
|
|
1279
|
+
return PICKLIST_MODES;
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1118
1282
|
Object.defineProperty(exports, "checkGenerated", {
|
|
1119
1283
|
enumerable: true,
|
|
1120
1284
|
get: function() {
|
|
@@ -1206,4 +1370,4 @@ Object.defineProperty(exports, "validateConfig", {
|
|
|
1206
1370
|
}
|
|
1207
1371
|
});
|
|
1208
1372
|
|
|
1209
|
-
//# sourceMappingURL=codegen-
|
|
1373
|
+
//# sourceMappingURL=codegen-Bylrt2Ju.cjs.map
|