@amerilux/netsuite-api 0.4.0 → 0.6.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 +101 -6
- package/dist/client/index.d.ts +1 -1
- package/dist/index.d.ts +137 -0
- package/dist/server/apiError.d.ts +2 -0
- package/dist/server/apiError.js +4 -0
- package/dist/server/defineJob.d.ts +95 -0
- package/dist/server/defineJob.js +150 -0
- package/dist/server/index.d.ts +8 -3
- package/dist/server/index.js +5 -2
- package/dist/server/jobRuns.d.ts +65 -0
- package/dist/server/jobRuns.js +292 -0
- package/dist/testing/N/task.d.ts +14 -0
- package/dist/testing/N/task.js +4 -1
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/jobs.d.ts +50 -0
- package/dist/testing/jobs.js +90 -0
- package/dist-tooling/cli/main.js +6 -3
- package/dist-tooling/config.d.ts +33 -0
- package/dist-tooling/config.js +91 -3
- package/dist-tooling/controllerReader.d.ts +22 -0
- package/dist-tooling/controllerReader.js +5 -5
- package/dist-tooling/emit.d.ts +42 -0
- package/dist-tooling/emit.js +126 -3
- package/dist-tooling/file-system.d.ts +2 -0
- package/dist-tooling/file-system.js +23 -0
- package/dist-tooling/generate.d.ts +10 -1
- package/dist-tooling/generate.js +145 -25
- package/dist-tooling/index.d.ts +7 -4
- package/dist-tooling/index.js +3 -1
- package/dist-tooling/jobReader.d.ts +83 -0
- package/dist-tooling/jobReader.js +386 -0
- package/package.json +1 -1
package/dist-tooling/generate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as nodePath from 'node:path';
|
|
2
|
-
import { resolveInlineTypesFile } from './config.js';
|
|
2
|
+
import { resolveInlineTypesFile, resolveJobRunFieldIds } from './config.js';
|
|
3
3
|
import { isControllerFileName, readControllerContract } from './controllerReader.js';
|
|
4
|
-
import { CLIENT_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitScriptsModule, sortControllers } from './emit.js';
|
|
4
|
+
import { CLIENT_INDEX_FILE_NAME, JOBS_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitJobModule, emitJobsIndexModule, emitScriptsModule, jobModuleFileName, sortControllers, sortJobs, } from './emit.js';
|
|
5
|
+
import { jobDefinitionFileName, readJobContract, readJobFolderName } from './jobReader.js';
|
|
5
6
|
import { toPosixPath } from './file-system.js';
|
|
6
7
|
import { readInlinableTypesFile, selectInlinedTypes } from './typesFileReader.js';
|
|
7
8
|
import { readReferencedNames } from './wireTypes.js';
|
|
@@ -9,35 +10,71 @@ const generatedFileNamePattern = /\.gen\.ts$/;
|
|
|
9
10
|
function relativeLabel(rootDirectory, filePath) {
|
|
10
11
|
return toPosixPath(nodePath.relative(rootDirectory, filePath));
|
|
11
12
|
}
|
|
12
|
-
function findDuplicateScriptIds(controllers) {
|
|
13
|
+
function findDuplicateScriptIds(controllers, jobs) {
|
|
13
14
|
const problems = [];
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
const scriptOwners = new Map();
|
|
16
|
+
const deployOwners = new Map();
|
|
17
|
+
const claim = (owners, id, filePath, label) => {
|
|
18
|
+
const owner = owners.get(id);
|
|
19
|
+
if (owner !== undefined)
|
|
20
|
+
problems.push({ filePath, message: `${label} '${id}' is also declared by ${owner}; every controller and every job is its own script.` });
|
|
21
|
+
else
|
|
22
|
+
owners.set(id, filePath);
|
|
23
|
+
};
|
|
24
|
+
for (const { contract } of controllers) {
|
|
25
|
+
claim(scriptOwners, contract.script.scriptId, contract.filePath, 'scriptId');
|
|
26
|
+
claim(deployOwners, contract.script.deployId, contract.filePath, 'deployId');
|
|
27
|
+
}
|
|
28
|
+
for (const { contract } of jobs) {
|
|
29
|
+
claim(scriptOwners, contract.script.scriptId, contract.filePath, 'scriptId');
|
|
30
|
+
for (const deployment of contract.script.deployments)
|
|
31
|
+
claim(deployOwners, deployment, contract.filePath, 'deployment');
|
|
24
32
|
}
|
|
25
33
|
return problems;
|
|
26
34
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
* ones: the handler would receive an ISO string where its annotation promises a Date. (A shape taken
|
|
30
|
-
* from a sibling controller is checked where it is declared, as that controller's own request.)
|
|
31
|
-
*/
|
|
32
|
-
function findDatesInRequestShapes(contract, inlinedTypes, controllerLabel) {
|
|
35
|
+
/** Every type declaration a shape can be built from: the file's own, then the ones copied into it. */
|
|
36
|
+
function collectDeclarations(own, inlinedTypes) {
|
|
33
37
|
const declarations = new Map();
|
|
34
|
-
for (const declaration of
|
|
38
|
+
for (const declaration of own)
|
|
35
39
|
declarations.set(declaration.name, declaration.text);
|
|
36
40
|
for (const section of inlinedTypes) {
|
|
37
41
|
for (const declaration of section.declarations)
|
|
38
42
|
if (!declarations.has(declaration.name))
|
|
39
43
|
declarations.set(declaration.name, declaration.text);
|
|
40
44
|
}
|
|
45
|
+
return declarations;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A Date reached from a run's input: it is stored as JSON on the run record, so the stage would
|
|
49
|
+
* receive an ISO string where its annotation promises a Date. The result is not checked, because
|
|
50
|
+
* nothing reads it back as a Date; the browser sees whatever summarize wrote.
|
|
51
|
+
*/
|
|
52
|
+
function findDatesInJobInput(contract, inlinedTypes, jobLabel) {
|
|
53
|
+
if (contract.inputType === undefined)
|
|
54
|
+
return [];
|
|
55
|
+
const declarations = collectDeclarations(contract.typeDeclarations, inlinedTypes);
|
|
56
|
+
const visited = new Set();
|
|
57
|
+
const pending = readReferencedNames(contract.inputType, 'type').map((name) => ({ name, via: contract.inputType }));
|
|
58
|
+
while (pending.length > 0) {
|
|
59
|
+
const { name, via } = pending.shift();
|
|
60
|
+
if (name === 'Date') {
|
|
61
|
+
return [{ filePath: jobLabel, message: `getInputData takes a Date in its input (through ${via}); a run carries its input as JSON, so take a string and parse it in the stage.` }];
|
|
62
|
+
}
|
|
63
|
+
const text = declarations.get(name);
|
|
64
|
+
if (text === undefined || visited.has(name))
|
|
65
|
+
continue;
|
|
66
|
+
visited.add(name);
|
|
67
|
+
pending.push(...readReferencedNames(text, 'declaration').map((reference) => ({ name: reference, via: name })));
|
|
68
|
+
}
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* A Date reached from a request shape, through the controller's own declarations and the copied
|
|
73
|
+
* ones: the handler would receive an ISO string where its annotation promises a Date. (A shape taken
|
|
74
|
+
* from a sibling controller is checked where it is declared, as that controller's own request.)
|
|
75
|
+
*/
|
|
76
|
+
function findDatesInRequestShapes(contract, inlinedTypes, controllerLabel) {
|
|
77
|
+
const declarations = collectDeclarations(contract.typeDeclarations, inlinedTypes);
|
|
41
78
|
const problems = [];
|
|
42
79
|
for (const endpoint of contract.endpoints) {
|
|
43
80
|
if (endpoint.requestType === undefined)
|
|
@@ -132,7 +169,78 @@ export function planClientGeneration({ config, fileSystem }) {
|
|
|
132
169
|
problems.push(...findDatesInRequestShapes(contract, inlinedTypes, controllerLabel));
|
|
133
170
|
emitted.push({ contract, sourceLabel: controllerLabel, inlinedTypes });
|
|
134
171
|
}
|
|
135
|
-
|
|
172
|
+
// Jobs: the same reading, with a run instead of a request and a record instead of a reply. A job is a
|
|
173
|
+
// folder — <name>/<name>.ts declares it and its stage files sit beside it — so the shapes on either end
|
|
174
|
+
// of a run are read wherever the stage that names them lives.
|
|
175
|
+
const jobsDirectory = resolve(config.jobs);
|
|
176
|
+
const emittedJobs = [];
|
|
177
|
+
/** Copies what one type import names into the job's sections, following imports between the files it reaches. */
|
|
178
|
+
function addInlinedTypes(sections, typeImport, fromLabel) {
|
|
179
|
+
const file = readInlinable(typeImport.specifier);
|
|
180
|
+
if (!file || file === 'missing')
|
|
181
|
+
return;
|
|
182
|
+
const selected = selectInlinedTypes(file, typeImport.names, fromLabel, readInlinable);
|
|
183
|
+
problems.push(...selected.problems);
|
|
184
|
+
for (const selectedSection of selected.sections)
|
|
185
|
+
addDeclarations(sections, selectedSection.filePath, selectedSection.declarations);
|
|
186
|
+
}
|
|
187
|
+
/** One section per source file, so a shape copied twice is written once. */
|
|
188
|
+
function addDeclarations(sections, sourceLabel, declarations) {
|
|
189
|
+
const section = sections.find((existing) => existing.sourceLabel === sourceLabel);
|
|
190
|
+
if (section)
|
|
191
|
+
section.declarations.push(...declarations.filter((declaration) => !section.declarations.some((existing) => existing.name === declaration.name)));
|
|
192
|
+
else
|
|
193
|
+
sections.push({ sourceLabel, declarations: [...declarations] });
|
|
194
|
+
}
|
|
195
|
+
for (const strayPath of fileSystem.listFiles(jobsDirectory)) {
|
|
196
|
+
problems.push({ filePath: label(strayPath), message: 'a job lives in a folder of its own, declared by the file of that name; nothing sits in the jobs folder itself.' });
|
|
197
|
+
}
|
|
198
|
+
for (const jobDirectory of fileSystem.listDirectories(jobsDirectory)) {
|
|
199
|
+
const jobName = readJobFolderName(nodePath.basename(jobDirectory));
|
|
200
|
+
if (jobName === undefined) {
|
|
201
|
+
problems.push({ filePath: label(jobDirectory), message: 'a job folder is named for its job, in camelCase.' });
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const definitionPath = nodePath.join(jobDirectory, jobDefinitionFileName(jobName));
|
|
205
|
+
if (!fileSystem.fileExists(definitionPath)) {
|
|
206
|
+
problems.push({ filePath: label(jobDirectory), message: `there is no ${jobDefinitionFileName(jobName)} here; the file of the folder's own name is what declares the job.` });
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const jobLabel = label(definitionPath);
|
|
210
|
+
const result = readJobContract(jobLabel, fileSystem.readTextFile(definitionPath), {
|
|
211
|
+
typeImports: config.typeImports,
|
|
212
|
+
inlineTypes: config.inlineTypes,
|
|
213
|
+
readStageFile: (specifier) => {
|
|
214
|
+
const stagePath = `${nodePath.resolve(jobDirectory, specifier)}.ts`;
|
|
215
|
+
return fileSystem.fileExists(stagePath) ? { filePath: label(stagePath), source: fileSystem.readTextFile(stagePath) } : undefined;
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
problems.push(...result.problems);
|
|
219
|
+
const contract = result.contract;
|
|
220
|
+
if (!contract)
|
|
221
|
+
continue;
|
|
222
|
+
if (controllerNames.has(contract.name) && jobModuleFileName(contract.name) === controllerModuleFileName(contract.name)) {
|
|
223
|
+
problems.push({ filePath: jobLabel, message: `a controller is named '${contract.name}' too; their generated modules would be the same file.` });
|
|
224
|
+
}
|
|
225
|
+
const inlinedTypes = [];
|
|
226
|
+
// A stage file's own shapes, then whatever it takes from a service: both are the run's, written where its stages are.
|
|
227
|
+
for (const stageFile of contract.stageFiles) {
|
|
228
|
+
addDeclarations(inlinedTypes, stageFile.filePath, stageFile.declarations);
|
|
229
|
+
for (const typeImport of stageFile.inlinedTypeImports)
|
|
230
|
+
addInlinedTypes(inlinedTypes, typeImport, stageFile.filePath);
|
|
231
|
+
}
|
|
232
|
+
for (const typeImport of contract.inlinedTypeImports)
|
|
233
|
+
addInlinedTypes(inlinedTypes, typeImport, jobLabel);
|
|
234
|
+
problems.push(...findDatesInJobInput(contract, inlinedTypes, jobLabel));
|
|
235
|
+
emittedJobs.push({ contract, sourceLabel: jobLabel, inlinedTypes });
|
|
236
|
+
}
|
|
237
|
+
if (emittedJobs.length > 0 && config.jobRuns === undefined) {
|
|
238
|
+
problems.push({
|
|
239
|
+
filePath: label(jobsDirectory),
|
|
240
|
+
message: 'the project has jobs but no run record: add the `jobRuns` block to netsuite-api.config.json (`npm run add:jobs` writes it, with the record itself).',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
problems.push(...findDuplicateScriptIds(emitted, emittedJobs));
|
|
136
244
|
const controllers = emitted.map(({ contract }) => ({
|
|
137
245
|
name: contract.name,
|
|
138
246
|
filePath: contract.filePath,
|
|
@@ -140,19 +248,31 @@ export function planClientGeneration({ config, fileSystem }) {
|
|
|
140
248
|
browser: contract.script.browser,
|
|
141
249
|
endpointCount: contract.endpoints.length,
|
|
142
250
|
}));
|
|
251
|
+
const jobs = emittedJobs.map(({ contract }) => ({
|
|
252
|
+
name: contract.name,
|
|
253
|
+
filePath: contract.filePath,
|
|
254
|
+
stages: contract.stages,
|
|
255
|
+
deploymentCount: contract.script.deployments.length,
|
|
256
|
+
}));
|
|
143
257
|
if (problems.length > 0)
|
|
144
|
-
return { files: [], leftoverFiles: [], controllers, problems };
|
|
258
|
+
return { files: [], leftoverFiles: [], controllers, jobs, problems };
|
|
145
259
|
const controllersLabel = label(controllersDirectory);
|
|
260
|
+
const jobsLabel = label(jobsDirectory);
|
|
261
|
+
const jobRuns = config.jobRuns
|
|
262
|
+
? { recordType: config.jobRuns.recordType, fields: resolveJobRunFieldIds(config.jobRuns), extraFields: config.jobRuns.extraFields ?? {} }
|
|
263
|
+
: undefined;
|
|
146
264
|
const files = [
|
|
147
265
|
...sortControllers(emitted).map((controller) => ({
|
|
148
266
|
path: nodePath.join(outDirectory, controllerModuleFileName(controller.contract.name)),
|
|
149
267
|
content: emitControllerModule(controller, { clientModule: config.clientModule }),
|
|
150
268
|
})),
|
|
151
|
-
{ path: nodePath.join(outDirectory,
|
|
152
|
-
{ path:
|
|
269
|
+
...sortJobs(emittedJobs).map((job) => ({ path: nodePath.join(outDirectory, jobModuleFileName(job.contract.name)), content: emitJobModule(job) })),
|
|
270
|
+
...(emittedJobs.length > 0 ? [{ path: nodePath.join(outDirectory, JOBS_INDEX_FILE_NAME), content: emitJobsIndexModule(emittedJobs, { jobsLabel }) }] : []),
|
|
271
|
+
{ path: nodePath.join(outDirectory, CLIENT_INDEX_FILE_NAME), content: emitClientIndexModule(emitted, { controllersLabel, hasJobs: emittedJobs.length > 0 }) },
|
|
272
|
+
{ path: resolve(config.scriptsOutFile), content: emitScriptsModule(emitted, { wireModule: config.wireModule, controllersLabel, jobs: emittedJobs, jobsLabel, jobRuns }) },
|
|
153
273
|
];
|
|
154
274
|
const leftoverFiles = findLeftoverFiles(fileSystem, outDirectory, files.map((file) => file.path));
|
|
155
|
-
return { files, leftoverFiles, controllers, problems };
|
|
275
|
+
return { files, leftoverFiles, controllers, jobs, problems };
|
|
156
276
|
}
|
|
157
277
|
export function runClientGeneration(options) {
|
|
158
278
|
const plan = planClientGeneration(options);
|
package/dist-tooling/index.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
/** The generator as a library: what the `netsuite-api` command runs, for a build tool or a test to call directly. */
|
|
2
2
|
export { DEFAULT_CONFIG_FILE_NAME, ClientGeneratorConfigError, defaultClientGeneratorConfig, loadClientGeneratorConfig } from './config.js';
|
|
3
|
-
export
|
|
3
|
+
export { JOB_RUN_FIELD_SUFFIXES, netsuiteValueTypeNames, resolveJobRunFieldIds } from './config.js';
|
|
4
|
+
export type { ClientGeneratorConfig, JobRunFieldName, JobRunsSettings, NetsuiteValueTypeName, ResolvedClientGeneratorConfig } from './config.js';
|
|
4
5
|
export { GENERATED_CLIENT_NAME, GENERATED_ENDPOINTS_TYPE_NAME, RAW_RESPONSE_TYPE_NAME, isControllerFileName, readControllerContract, readLeadingJsDoc } from './controllerReader.js';
|
|
5
6
|
export type { CarriedTypeImport, ControllerContract, ControllerKind, ControllerProblem, ControllerReadResult, ControllerTypeImport, DeclaredScript, EndpointSignature, InlinedTypeImport, ReadControllerOptions, TypeDeclaration, TypeImportName } from './controllerReader.js';
|
|
7
|
+
export { GENERATED_JOB_RESULT_TYPE_NAME, JOB_SCRIPT_TYPE_HEADER, JOB_STAGE_NAMES, jobDefinitionFileName, readJobContract, readJobFolderName } from './jobReader.js';
|
|
8
|
+
export type { DeclaredJob, JobContract, JobParameterContract, JobReadResult, JobStageName } from './jobReader.js';
|
|
6
9
|
export { readInlinableTypesFile, selectInlinedTypes } from './typesFileReader.js';
|
|
7
10
|
export type { InlinableTypeDeclaration, InlinableTypesFile, SelectedInlinedTypes } from './typesFileReader.js';
|
|
8
|
-
export { CLIENT_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitScriptsModule } from './emit.js';
|
|
9
|
-
export type { EmitClientIndexModuleOptions, EmitControllerModuleOptions, EmitScriptsModuleOptions, EmittedController, InlinedTypeSection } from './emit.js';
|
|
11
|
+
export { CLIENT_INDEX_FILE_NAME, JOBS_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitJobModule, emitJobsIndexModule, emitScriptsModule, jobModuleFileName } from './emit.js';
|
|
12
|
+
export type { EmitClientIndexModuleOptions, EmitControllerModuleOptions, EmitScriptsModuleOptions, EmittedController, EmittedJob, EmittedJobRuns, InlinedTypeSection } from './emit.js';
|
|
10
13
|
export { checkClientGeneration, planClientGeneration, runClientGeneration } from './generate.js';
|
|
11
|
-
export type { ClientGenerationCheck, ClientGenerationPlan, ClientGenerationResult, GenerateClientOptions, PlannedController, PlannedFile } from './generate.js';
|
|
14
|
+
export type { ClientGenerationCheck, ClientGenerationPlan, ClientGenerationResult, GenerateClientOptions, PlannedController, PlannedFile, PlannedJob } from './generate.js';
|
|
12
15
|
export { createInMemoryFileSystemAdapter, createNodeFileSystemAdapter, toPosixPath } from './file-system.js';
|
|
13
16
|
export type { FileSystemAdapter, InMemoryFileSystemAdapter } from './file-system.js';
|
|
14
17
|
export { CLI_USAGE, EXIT_PROBLEMS, EXIT_SUCCESS, EXIT_USAGE, runCli } from './cli/main.js';
|
package/dist-tooling/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/** The generator as a library: what the `netsuite-api` command runs, for a build tool or a test to call directly. */
|
|
2
2
|
export { DEFAULT_CONFIG_FILE_NAME, ClientGeneratorConfigError, defaultClientGeneratorConfig, loadClientGeneratorConfig } from './config.js';
|
|
3
|
+
export { JOB_RUN_FIELD_SUFFIXES, netsuiteValueTypeNames, resolveJobRunFieldIds } from './config.js';
|
|
3
4
|
export { GENERATED_CLIENT_NAME, GENERATED_ENDPOINTS_TYPE_NAME, RAW_RESPONSE_TYPE_NAME, isControllerFileName, readControllerContract, readLeadingJsDoc } from './controllerReader.js';
|
|
5
|
+
export { GENERATED_JOB_RESULT_TYPE_NAME, JOB_SCRIPT_TYPE_HEADER, JOB_STAGE_NAMES, jobDefinitionFileName, readJobContract, readJobFolderName } from './jobReader.js';
|
|
4
6
|
export { readInlinableTypesFile, selectInlinedTypes } from './typesFileReader.js';
|
|
5
|
-
export { CLIENT_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitScriptsModule } from './emit.js';
|
|
7
|
+
export { CLIENT_INDEX_FILE_NAME, JOBS_INDEX_FILE_NAME, controllerModuleFileName, emitClientIndexModule, emitControllerModule, emitJobModule, emitJobsIndexModule, emitScriptsModule, jobModuleFileName } from './emit.js';
|
|
6
8
|
export { checkClientGeneration, planClientGeneration, runClientGeneration } from './generate.js';
|
|
7
9
|
export { createInMemoryFileSystemAdapter, createNodeFileSystemAdapter, toPosixPath } from './file-system.js';
|
|
8
10
|
export { CLI_USAGE, EXIT_PROBLEMS, EXIT_SUCCESS, EXIT_USAGE, runCli } from './cli/main.js';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { CarriedTypeImport, ControllerProblem, InlinedTypeImport, ReadControllerOptions, TypeDeclaration } from './controllerReader.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reads what a job run carries: the script it declares in its defineJob call, the stages it has, and
|
|
4
|
+
* the types on either end of a run. A run's input is the first parameter of getInputData and its result
|
|
5
|
+
* is what summarize returns, so those two annotations are the contract, the way a handler's parameter
|
|
6
|
+
* and return type are a controller's. A parse, not a type check: the ids are string literals and the
|
|
7
|
+
* shapes are written out.
|
|
8
|
+
*
|
|
9
|
+
* A job is a folder — `<name>/<name>.ts` declares it — and a stage is either a function written inline
|
|
10
|
+
* or one imported from a file beside it (`./map`), which is where the annotations are then read from. So
|
|
11
|
+
* a developer opens map.ts to see what the map stage does, and the definition file stays a declaration.
|
|
12
|
+
*/
|
|
13
|
+
/** The stage names a job may declare, in the order NetSuite calls them. */
|
|
14
|
+
export declare const JOB_STAGE_NAMES: readonly ["getInputData", "map", "reduce", "summarize"];
|
|
15
|
+
export type JobStageName = (typeof JOB_STAGE_NAMES)[number];
|
|
16
|
+
/** The script type a job's leading JSDoc must declare. */
|
|
17
|
+
export declare const JOB_SCRIPT_TYPE_HEADER = "MapReduceScript";
|
|
18
|
+
/** The type the generated job module gives the run's input, and the one it gives the result. */
|
|
19
|
+
export declare const GENERATED_JOB_RESULT_TYPE_NAME = "Result";
|
|
20
|
+
declare const netsuiteValueTypes: readonly ["text", "integer", "decimal", "checkbox", "date", "select"];
|
|
21
|
+
export interface JobParameterContract {
|
|
22
|
+
/** The name the stages read it by. */
|
|
23
|
+
name: string;
|
|
24
|
+
id: string;
|
|
25
|
+
type: (typeof netsuiteValueTypes)[number];
|
|
26
|
+
}
|
|
27
|
+
/** The script a job declares, as read off its defineJob call. */
|
|
28
|
+
export interface DeclaredJob {
|
|
29
|
+
scriptId: string;
|
|
30
|
+
deployments: string[];
|
|
31
|
+
runParameter: string;
|
|
32
|
+
parameters: JobParameterContract[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A file a stage was read from: what it declares, and the type imports it carries. Its declarations are
|
|
36
|
+
* copied into the browser's module like a service's, because a run's shapes are written where its stages are.
|
|
37
|
+
*/
|
|
38
|
+
export interface JobStageFile {
|
|
39
|
+
filePath: string;
|
|
40
|
+
declarations: TypeDeclaration[];
|
|
41
|
+
inlinedTypeImports: InlinedTypeImport[];
|
|
42
|
+
carriedTypeImports: CarriedTypeImport[];
|
|
43
|
+
}
|
|
44
|
+
/** What a job's reader needs beyond a controller's: the files its stages are imported from. */
|
|
45
|
+
export interface ReadJobOptions extends ReadControllerOptions {
|
|
46
|
+
/**
|
|
47
|
+
* Reads a file a stage is imported from, the specifier resolved against the job's own folder, or
|
|
48
|
+
* undefined when there is no such file. Without it, only inline stages can be read.
|
|
49
|
+
*/
|
|
50
|
+
readStageFile?(specifier: string): {
|
|
51
|
+
filePath: string;
|
|
52
|
+
source: string;
|
|
53
|
+
} | undefined;
|
|
54
|
+
}
|
|
55
|
+
export interface JobContract {
|
|
56
|
+
/** The job's name: `closeStaleOrders` for closeStaleOrders.ts, matching `name` in its declaration. */
|
|
57
|
+
name: string;
|
|
58
|
+
filePath: string;
|
|
59
|
+
script: DeclaredJob;
|
|
60
|
+
carriedTypeImports: CarriedTypeImport[];
|
|
61
|
+
inlinedTypeImports: InlinedTypeImport[];
|
|
62
|
+
typeDeclarations: TypeDeclaration[];
|
|
63
|
+
/** The type of getInputData's first parameter, or undefined when a run takes no input. */
|
|
64
|
+
inputType?: string;
|
|
65
|
+
/** What summarize returns, or undefined when the job has no summarize stage of its own. */
|
|
66
|
+
resultType?: string;
|
|
67
|
+
/** The stages the job declares. */
|
|
68
|
+
stages: JobStageName[];
|
|
69
|
+
/** The stages the file exports as NetSuite entry points. */
|
|
70
|
+
exportedStages: string[];
|
|
71
|
+
/** The files the stages were imported from, in the order they were read. */
|
|
72
|
+
stageFiles: JobStageFile[];
|
|
73
|
+
}
|
|
74
|
+
export interface JobReadResult {
|
|
75
|
+
contract?: JobContract;
|
|
76
|
+
problems: ControllerProblem[];
|
|
77
|
+
}
|
|
78
|
+
/** The name a job folder declares: `approveOrders` for api/src/jobs/approveOrders, or undefined when it is not a name. */
|
|
79
|
+
export declare function readJobFolderName(folderName: string): string | undefined;
|
|
80
|
+
/** The file that declares the job of a folder: the folder's own name again, so the file is unique to open and to search for. */
|
|
81
|
+
export declare function jobDefinitionFileName(jobName: string): string;
|
|
82
|
+
export declare function readJobContract(filePath: string, source: string, options: ReadJobOptions): JobReadResult;
|
|
83
|
+
export {};
|