@openrouter/sdk 1.3.21 → 1.3.22
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/esm/funcs/alphaDecisionsCreate.js +5 -5
- package/esm/funcs/analyticsGetAnalyticsMeta.js +4 -4
- package/esm/funcs/analyticsGetUserActivity.js +5 -5
- package/esm/funcs/analyticsQueryAnalytics.js +4 -4
- package/esm/funcs/apiKeysCreate.js +4 -4
- package/esm/funcs/apiKeysDelete.js +4 -4
- package/esm/funcs/apiKeysGet.js +4 -4
- package/esm/funcs/apiKeysGetCurrentKeyMetadata.js +4 -4
- package/esm/funcs/apiKeysList.js +4 -4
- package/esm/funcs/apiKeysUpdate.js +4 -4
- package/esm/funcs/benchmarksGetBenchmarks.js +5 -5
- package/esm/funcs/byokCreate.js +5 -5
- package/esm/funcs/byokDelete.js +5 -5
- package/esm/funcs/byokGet.js +5 -5
- package/esm/funcs/byokList.js +5 -5
- package/esm/funcs/byokUpdate.js +5 -5
- package/esm/funcs/chatSend.js +4 -4
- package/esm/funcs/classificationsGetTaskClassifications.js +5 -5
- package/esm/funcs/containersDownloadContainerFileContent.js +4 -4
- package/esm/funcs/containersGetContainerFile.js +5 -5
- package/esm/funcs/containersListContainerFiles.js +5 -5
- package/esm/funcs/containersPromoteContainerFile.js +5 -5
- package/esm/funcs/creditsGetCredits.js +4 -4
- package/esm/funcs/datasetsGetAppRankings.js +5 -5
- package/esm/funcs/datasetsGetRankingsDaily.js +5 -5
- package/esm/funcs/datasetsGetSessionCost.js +5 -5
- package/esm/funcs/embeddingsGenerate.js +5 -5
- package/esm/funcs/embeddingsListModels.js +5 -5
- package/esm/funcs/endpointsList.js +4 -4
- package/esm/funcs/endpointsListZdrEndpoints.js +4 -4
- package/esm/funcs/filesDelete.js +5 -5
- package/esm/funcs/filesDownload.js +4 -4
- package/esm/funcs/filesList.js +4 -4
- package/esm/funcs/filesRetrieve.js +5 -5
- package/esm/funcs/filesUpload.js +5 -5
- package/esm/funcs/generationsGetGeneration.js +5 -5
- package/esm/funcs/generationsListGenerationContent.js +5 -5
- package/esm/funcs/generationsSubmitFeedback.js +5 -5
- package/esm/funcs/guardrailsBulkAssignKeys.js +5 -5
- package/esm/funcs/guardrailsBulkAssignMembers.js +5 -5
- package/esm/funcs/guardrailsBulkUnassignKeys.js +5 -5
- package/esm/funcs/guardrailsBulkUnassignMembers.js +5 -5
- package/esm/funcs/guardrailsCreate.js +5 -5
- package/esm/funcs/guardrailsDelete.js +5 -5
- package/esm/funcs/guardrailsGet.js +5 -5
- package/esm/funcs/guardrailsList.js +5 -5
- package/esm/funcs/guardrailsListGuardrailKeyAssignments.js +5 -5
- package/esm/funcs/guardrailsListGuardrailMemberAssignments.js +4 -4
- package/esm/funcs/guardrailsListKeyAssignments.js +5 -5
- package/esm/funcs/guardrailsListMemberAssignments.js +5 -5
- package/esm/funcs/guardrailsUpdate.js +5 -5
- package/esm/funcs/imagesGenerate.js +4 -4
- package/esm/funcs/imagesListModelEndpoints.js +5 -5
- package/esm/funcs/imagesListModels.js +5 -5
- package/esm/funcs/internsChat.js +8 -8
- package/esm/funcs/internsCreateIntern.js +5 -5
- package/esm/funcs/internsDeleteIntern.js +5 -5
- package/esm/funcs/internsGetIntern.js +5 -5
- package/esm/funcs/internsInvoke.js +7 -7
- package/esm/funcs/internsListInterns.js +5 -5
- package/esm/funcs/internsProvisionIntern.js +5 -5
- package/esm/funcs/internsSuspendIntern.js +5 -5
- package/esm/funcs/internsUpdateIntern.js +5 -5
- package/esm/funcs/modelsCount.js +5 -5
- package/esm/funcs/modelsGet.js +5 -5
- package/esm/funcs/modelsList.js +4 -4
- package/esm/funcs/modelsListForUser.js +5 -5
- package/esm/funcs/oAuthCreateAuthCode.js +4 -4
- package/esm/funcs/oAuthCreateOauthToken.js +5 -5
- package/esm/funcs/oAuthExchangeAuthCodeForAPIKey.js +4 -4
- package/esm/funcs/oAuthListOauthJwks.js +5 -5
- package/esm/funcs/observabilityCreate.js +5 -5
- package/esm/funcs/observabilityDelete.js +5 -5
- package/esm/funcs/observabilityGet.js +5 -5
- package/esm/funcs/observabilityList.js +4 -4
- package/esm/funcs/observabilityUpdate.js +5 -5
- package/esm/funcs/organizationListMembers.js +5 -5
- package/esm/funcs/presetsCreatePresetsChatCompletions.js +5 -5
- package/esm/funcs/presetsCreatePresetsMessages.js +5 -5
- package/esm/funcs/presetsCreatePresetsResponses.js +5 -5
- package/esm/funcs/presetsGet.js +5 -5
- package/esm/funcs/presetsGetVersion.js +5 -5
- package/esm/funcs/presetsList.js +5 -5
- package/esm/funcs/presetsListVersions.js +5 -5
- package/esm/funcs/providersList.js +4 -4
- package/esm/funcs/rerankRerank.js +5 -5
- package/esm/funcs/responsesSend.js +4 -4
- package/esm/funcs/scimCreate.js +5 -5
- package/esm/funcs/scimCreateSyncJob.js +5 -5
- package/esm/funcs/scimDelete.js +5 -5
- package/esm/funcs/scimGetSyncJob.js +5 -5
- package/esm/funcs/scimListGroups.js +5 -5
- package/esm/funcs/scimListMappings.js +5 -5
- package/esm/funcs/scimRead.js +5 -5
- package/esm/funcs/scimUpdate.js +5 -5
- package/esm/funcs/sttCreateTranscription.js +5 -5
- package/esm/funcs/sttCreateTranscriptionMultipart.js +5 -5
- package/esm/funcs/systemOneCreate.js +5 -5
- package/esm/funcs/ttsCreateSpeech.js +4 -4
- package/esm/funcs/vaultCopyVaultSecretsToIntern.js +5 -5
- package/esm/funcs/vaultDeleteInternVaultSecret.js +4 -4
- package/esm/funcs/vaultDeleteVaultSecret.js +4 -4
- package/esm/funcs/vaultListInternVaultSecrets.js +5 -5
- package/esm/funcs/vaultListVaultSecrets.js +5 -5
- package/esm/funcs/vaultStoreInternVaultSecret.js +5 -5
- package/esm/funcs/vaultStoreVaultSecret.js +5 -5
- package/esm/funcs/videoGenerationGenerate.js +5 -5
- package/esm/funcs/videoGenerationGetGeneration.js +5 -5
- package/esm/funcs/videoGenerationGetVideoContent.js +4 -4
- package/esm/funcs/videoGenerationListVideosModels.js +5 -5
- package/esm/funcs/workspacesBulkAddMembers.js +5 -5
- package/esm/funcs/workspacesBulkRemoveMembers.js +5 -5
- package/esm/funcs/workspacesCreate.js +5 -5
- package/esm/funcs/workspacesDelete.js +5 -5
- package/esm/funcs/workspacesDeleteBudget.js +5 -5
- package/esm/funcs/workspacesGet.js +5 -5
- package/esm/funcs/workspacesGetBudget.js +5 -5
- package/esm/funcs/workspacesList.js +5 -5
- package/esm/funcs/workspacesListBudgets.js +5 -5
- package/esm/funcs/workspacesListMembers.js +5 -5
- package/esm/funcs/workspacesSetBudget.js +5 -5
- package/esm/funcs/workspacesUpdate.js +5 -5
- package/esm/lib/anthropic-compat.d.ts +2 -2
- package/esm/lib/async-params.d.ts +4 -4
- package/esm/lib/chat-compat.d.ts +3 -2
- package/esm/lib/config.d.ts +2 -2
- package/esm/lib/config.js +2 -2
- package/esm/lib/conversation-state.d.ts +7 -5
- package/esm/lib/model-result.d.ts +7 -4
- package/esm/lib/next-turn-params.d.ts +4 -4
- package/esm/lib/stream-transformers.d.ts +26 -17
- package/esm/lib/stream-type-guards.d.ts +41 -21
- package/esm/lib/tool-orchestrator.d.ts +7 -5
- package/esm/lib/tool-types.d.ts +14 -10
- package/esm/lib/turn-context.d.ts +6 -4
- package/esm/lib/turn-context.js +2 -2
- package/esm/models/customtoolcallitem.d.ts +8 -8
- package/esm/models/customtoolcallitem.js +4 -4
- package/esm/models/errors/badgatewayresponseerror.js +2 -2
- package/esm/models/errors/badrequestresponseerror.js +2 -2
- package/esm/models/errors/conflictresponseerror.js +2 -2
- package/esm/models/errors/edgenetworktimeoutresponseerror.js +2 -2
- package/esm/models/errors/forbiddenresponseerror.js +2 -2
- package/esm/models/errors/gatewaytimeoutresponseerror.js +2 -2
- package/esm/models/errors/goneresponseerror.js +2 -2
- package/esm/models/errors/internalserverresponseerror.js +2 -2
- package/esm/models/errors/internchaterrorresponse.js +2 -2
- package/esm/models/errors/internlifecycleerror.js +2 -2
- package/esm/models/errors/notfoundresponseerror.js +2 -2
- package/esm/models/errors/oautherrorresponse.js +2 -2
- package/esm/models/errors/payloadtoolargeresponseerror.js +2 -2
- package/esm/models/errors/paymentrequiredresponseerror.js +2 -2
- package/esm/models/errors/provideroverloadedresponseerror.js +2 -2
- package/esm/models/errors/requesttimeoutresponseerror.js +2 -2
- package/esm/models/errors/serviceunavailableresponseerror.js +2 -2
- package/esm/models/errors/toomanyrequestsresponseerror.js +2 -2
- package/esm/models/errors/unauthorizedresponseerror.js +2 -2
- package/esm/models/errors/unprocessableentityresponseerror.js +2 -2
- package/esm/models/functioncallitem.d.ts +12 -12
- package/esm/models/functioncallitem.js +6 -6
- package/esm/models/inputsunion.d.ts +4 -6
- package/esm/models/inputsunion.js +2 -8
- package/esm/models/operations/bulkaddworkspacemembers.js +2 -2
- package/esm/models/operations/bulkassignkeystoguardrail.js +2 -2
- package/esm/models/operations/bulkassignmemberstoguardrail.js +2 -2
- package/esm/models/operations/bulkremoveworkspacemembers.js +2 -2
- package/esm/models/operations/bulkunassignkeysfromguardrail.js +2 -2
- package/esm/models/operations/bulkunassignmembersfromguardrail.js +2 -2
- package/esm/models/operations/copyvaultsecretstointern.js +2 -2
- package/esm/models/operations/createapialphadecisions.js +2 -2
- package/esm/models/operations/createaudiospeech.js +2 -2
- package/esm/models/operations/createaudiotranscriptions.js +2 -2
- package/esm/models/operations/createbyokkey.js +2 -2
- package/esm/models/operations/createembeddings.js +10 -10
- package/esm/models/operations/createguardrail.js +2 -2
- package/esm/models/operations/createimages.js +4 -4
- package/esm/models/operations/createintern.js +2 -2
- package/esm/models/operations/createinternchatcompletion.js +6 -6
- package/esm/models/operations/createoauthtoken.js +2 -2
- package/esm/models/operations/createobservabilitydestination.js +2 -2
- package/esm/models/operations/createpresetschatcompletions.js +2 -2
- package/esm/models/operations/createpresetsmessages.js +2 -2
- package/esm/models/operations/createpresetsresponses.js +2 -2
- package/esm/models/operations/creatererank.js +3 -3
- package/esm/models/operations/createresponses.js +5 -5
- package/esm/models/operations/createscimgroupmapping.js +2 -2
- package/esm/models/operations/createscimsyncjob.js +2 -2
- package/esm/models/operations/createsystemone.js +2 -2
- package/esm/models/operations/createvideos.js +2 -2
- package/esm/models/operations/createworkspace.js +2 -2
- package/esm/models/operations/deletefile.js +2 -2
- package/esm/models/operations/deleteintern.js +2 -2
- package/esm/models/operations/deleteworkspacebudget.js +2 -2
- package/esm/models/operations/downloadfilecontent.js +2 -2
- package/esm/models/operations/getapprankings.js +2 -2
- package/esm/models/operations/getcurrentkey.js +2 -2
- package/esm/models/operations/getfilemetadata.js +2 -2
- package/esm/models/operations/getmodels.js +2 -2
- package/esm/models/operations/getsessioncost.js +2 -2
- package/esm/models/operations/getworkspacebudget.js +2 -2
- package/esm/models/operations/invokeintern.js +3 -3
- package/esm/models/operations/listbyokkeys.js +2 -2
- package/esm/models/operations/listembeddingsmodels.js +2 -2
- package/esm/models/operations/listendpoints.js +2 -2
- package/esm/models/operations/listendpointszdr.js +2 -2
- package/esm/models/operations/listfiles.js +3 -3
- package/esm/models/operations/listguardrailkeyassignments.js +2 -2
- package/esm/models/operations/listguardrailmemberassignments.js +2 -2
- package/esm/models/operations/listguardrails.js +2 -2
- package/esm/models/operations/listkeyassignments.js +2 -2
- package/esm/models/operations/listmemberassignments.js +2 -2
- package/esm/models/operations/listmodelsuser.js +2 -2
- package/esm/models/operations/listobservabilitydestinations.js +2 -2
- package/esm/models/operations/listpresets.js +2 -2
- package/esm/models/operations/listpresetversions.js +2 -2
- package/esm/models/operations/listscimgroupmappings.js +2 -2
- package/esm/models/operations/listscimgroups.js +2 -2
- package/esm/models/operations/listworkspacemembers.js +2 -2
- package/esm/models/operations/listworkspaces.js +2 -2
- package/esm/models/operations/sendchatcompletionrequest.js +5 -5
- package/esm/models/operations/storeinternvaultsecret.js +2 -2
- package/esm/models/operations/storevaultsecret.js +2 -2
- package/esm/models/operations/submitgenerationfeedback.js +2 -2
- package/esm/models/operations/updatebyokkey.js +2 -2
- package/esm/models/operations/updateguardrail.js +2 -2
- package/esm/models/operations/updateintern.js +2 -2
- package/esm/models/operations/updateobservabilitydestination.js +2 -2
- package/esm/models/operations/updatescimgroupmapping.js +2 -2
- package/esm/models/operations/updateworkspace.js +2 -2
- package/esm/models/operations/uploadfile.js +2 -2
- package/esm/models/operations/upsertworkspacebudget.js +3 -3
- package/esm/models/outputcustomtoolcallitem.d.ts +2 -26
- package/esm/models/outputcustomtoolcallitem.js +1 -28
- package/esm/models/outputfunctioncallitem.d.ts +1 -44
- package/esm/models/outputfunctioncallitem.js +1 -64
- package/esm/models/outputitems.d.ts +2 -6
- package/esm/models/outputitems.js +2 -2
- package/jsr.json +1 -1
- package/package.json +11 -9
- package/scripts/unbarrel-imports.js +296 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Rewrite namespace barrel imports in the compiled `esm/` output.
|
|
4
|
+
*
|
|
5
|
+
* Speakeasy's generated code imports models through namespace barrels
|
|
6
|
+
* (`import * as operations from "../models/operations/index.js"`). Under a
|
|
7
|
+
* dynamic `import()` in a single-file bundle, bundlers cannot prune those
|
|
8
|
+
* `export *` chains, so one function pulls in every model. This rewrites
|
|
9
|
+
* each such import into named imports from the module that defines each
|
|
10
|
+
* name, aliased as `<namespace>_<name>` so they never collide with local
|
|
11
|
+
* declarations. The barrels themselves stay, for public consumers.
|
|
12
|
+
*
|
|
13
|
+
* Runs after `tsc` on `esm/`, so Speakeasy's generated `src/` is untouched.
|
|
14
|
+
* The rewrite is layout-preserving: `ns.Name` becomes `ns_Name` (same length)
|
|
15
|
+
* and the replacement imports occupy the original import's line, so every
|
|
16
|
+
* other line and column is where tsc put it and `.js.map` files stay valid.
|
|
17
|
+
* It refuses, rather than guesses, on anything it cannot rewrite exactly.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
21
|
+
import path, { basename, dirname, join, relative, resolve, sep } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import ts from 'typescript';
|
|
24
|
+
|
|
25
|
+
export const ESM = join(resolve(dirname(fileURLToPath(import.meta.url)), '..'), 'esm');
|
|
26
|
+
|
|
27
|
+
/** Barrel directories, relative to the compiled root. */
|
|
28
|
+
const BARREL_DIRS = ['models', 'models/operations', 'models/errors'];
|
|
29
|
+
|
|
30
|
+
const barrelsIn = (root) => BARREL_DIRS.map((dir) => resolve(root, dir, 'index.js'));
|
|
31
|
+
|
|
32
|
+
class UnbarrelError extends Error {}
|
|
33
|
+
|
|
34
|
+
function fail(file, node, source, message) {
|
|
35
|
+
const at = node ? `:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}` : '';
|
|
36
|
+
throw new UnbarrelError(`${file}${at}: ${message}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parse(file) {
|
|
40
|
+
return ts.createSourceFile(file, readFileSync(file, 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Every `.js` file under `dir`, recursively. */
|
|
44
|
+
function listModules(dir) {
|
|
45
|
+
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
46
|
+
const full = join(dir, entry.name);
|
|
47
|
+
if (entry.isDirectory()) return listModules(full);
|
|
48
|
+
return entry.name.endsWith('.js') ? [full] : [];
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Resolve a relative specifier from `file` to an absolute module path. */
|
|
53
|
+
function resolveSpecifier(file, specifier) {
|
|
54
|
+
return specifier.startsWith('.') ? resolve(dirname(file), specifier) : undefined;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* A relative ESM specifier from `file` to `module`, always with `/` separators.
|
|
59
|
+
* `pathApi` is injectable so the Windows behavior can be tested on any OS.
|
|
60
|
+
*/
|
|
61
|
+
export function specifierFor(file, module, pathApi = path) {
|
|
62
|
+
const joined = pathApi.relative(pathApi.dirname(file), module).split(pathApi.sep).join('/');
|
|
63
|
+
return joined.startsWith('./') || joined.startsWith('../') ? joined : `./${joined}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const isExported = (statement) =>
|
|
67
|
+
ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) ?? false;
|
|
68
|
+
|
|
69
|
+
/** Names a leaf module defines, mapped to that module. Refuses forms it cannot follow. */
|
|
70
|
+
function moduleExports(module) {
|
|
71
|
+
const source = parse(module);
|
|
72
|
+
const names = new Map();
|
|
73
|
+
for (const statement of source.statements) {
|
|
74
|
+
if (ts.isExportDeclaration(statement)) {
|
|
75
|
+
const empty = !statement.moduleSpecifier && statement.exportClause && ts.isNamedExports(statement.exportClause)
|
|
76
|
+
&& statement.exportClause.elements.length === 0;
|
|
77
|
+
if (!empty) fail(module, statement, source, 'unsupported re-export in a model module');
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (ts.isExportAssignment(statement)) fail(module, statement, source, 'default export in a model module');
|
|
81
|
+
if (!isExported(statement)) continue;
|
|
82
|
+
if (ts.isVariableStatement(statement)) {
|
|
83
|
+
for (const decl of statement.declarationList.declarations) {
|
|
84
|
+
if (!ts.isIdentifier(decl.name)) fail(module, decl, source, 'destructured export');
|
|
85
|
+
names.set(decl.name.text, module);
|
|
86
|
+
}
|
|
87
|
+
} else if ((ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) && statement.name) {
|
|
88
|
+
names.set(statement.name.text, module);
|
|
89
|
+
} else {
|
|
90
|
+
fail(module, statement, source, 'unsupported export form');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return names;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Map each name exported by a barrel to the module that defines it, following
|
|
98
|
+
* nested `export * from` barrels. Throws on a duplicate definition.
|
|
99
|
+
*/
|
|
100
|
+
function barrelExports(barrel, seen = new Set()) {
|
|
101
|
+
if (seen.has(barrel)) return new Map();
|
|
102
|
+
seen.add(barrel);
|
|
103
|
+
const source = parse(barrel);
|
|
104
|
+
const names = new Map();
|
|
105
|
+
for (const statement of source.statements) {
|
|
106
|
+
const isStarExport = ts.isExportDeclaration(statement) && !statement.exportClause && statement.moduleSpecifier
|
|
107
|
+
&& ts.isStringLiteral(statement.moduleSpecifier);
|
|
108
|
+
if (!isStarExport) fail(barrel, statement, source, 'barrel may only contain `export * from "..."`');
|
|
109
|
+
const target = resolveSpecifier(barrel, statement.moduleSpecifier.text);
|
|
110
|
+
if (!target) fail(barrel, statement, source, 'barrel re-exports a package, expected a relative module');
|
|
111
|
+
const nested = target.endsWith(`${sep}index.js`) ? barrelExports(target, seen) : moduleExports(target);
|
|
112
|
+
for (const [name, module] of nested) {
|
|
113
|
+
const prior = names.get(name);
|
|
114
|
+
if (prior && prior !== module) fail(barrel, statement, source, `${name} is exported by both ${prior} and ${module}`);
|
|
115
|
+
names.set(name, module);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return names;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Namespace imports of one of `barrels` in `source`: `import * as ns from "<barrel>"`. */
|
|
122
|
+
function barrelImports(file, source, barrels) {
|
|
123
|
+
const found = [];
|
|
124
|
+
for (const statement of source.statements) {
|
|
125
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
126
|
+
const target = resolveSpecifier(file, statement.moduleSpecifier.text);
|
|
127
|
+
if (!target) continue;
|
|
128
|
+
const clause = statement.importClause;
|
|
129
|
+
const bindings = clause?.namedBindings;
|
|
130
|
+
if (!barrels.includes(target)) {
|
|
131
|
+
// A namespace import of some other index.js is likely a barrel this
|
|
132
|
+
// script does not know; refuse rather than leave it silently.
|
|
133
|
+
if (bindings && ts.isNamespaceImport(bindings) && basename(target) === 'index.js') {
|
|
134
|
+
fail(file, statement, source, `namespace import of unrecognized barrel ${statement.moduleSpecifier.text} (add it to BARREL_DIRS)`);
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (!clause || clause.name || !bindings || !ts.isNamespaceImport(bindings)) {
|
|
139
|
+
fail(file, statement, source, 'barrel imported in an unsupported form (expected `import * as ns`)');
|
|
140
|
+
}
|
|
141
|
+
found.push({ statement, namespace: bindings.name.text, barrel: target });
|
|
142
|
+
}
|
|
143
|
+
return found;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Every identifier name declared or referenced in `source`, to rule out alias collisions. */
|
|
147
|
+
function identifierNames(source) {
|
|
148
|
+
const names = new Set();
|
|
149
|
+
const visit = (node) => {
|
|
150
|
+
if (ts.isIdentifier(node)) names.add(node.text);
|
|
151
|
+
ts.forEachChild(node, visit);
|
|
152
|
+
};
|
|
153
|
+
visit(source);
|
|
154
|
+
return names;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Whether `node` names a property rather than referencing a binding. */
|
|
158
|
+
function isPropertyName(node) {
|
|
159
|
+
const parent = node.parent;
|
|
160
|
+
return (ts.isPropertyAccessExpression(parent) && parent.name === node)
|
|
161
|
+
|| ((ts.isPropertyAssignment(parent) || ts.isMethodDeclaration(parent) || ts.isPropertyDeclaration(parent)
|
|
162
|
+
|| ts.isGetAccessorDeclaration(parent) || ts.isSetAccessorDeclaration(parent)) && parent.name === node)
|
|
163
|
+
|| (ts.isBindingElement(parent) && parent.propertyName === node)
|
|
164
|
+
|| ((ts.isImportSpecifier(parent) || ts.isExportSpecifier(parent)) && parent.propertyName === node);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Rewrite one file's barrel imports. Returns the new source, or undefined when unchanged. */
|
|
168
|
+
function rewriteFile(file, exportsByBarrel) {
|
|
169
|
+
const source = parse(file);
|
|
170
|
+
const imports = barrelImports(file, source, [...exportsByBarrel.keys()]);
|
|
171
|
+
if (imports.length === 0) return undefined;
|
|
172
|
+
const byNamespace = new Map(imports.map((entry) => [entry.namespace, entry]));
|
|
173
|
+
if (byNamespace.size !== imports.length) fail(file, imports[0].statement, source, 'namespace bound twice');
|
|
174
|
+
const existing = identifierNames(source);
|
|
175
|
+
const used = new Map([...byNamespace.keys()].map((ns) => [ns, new Set()]));
|
|
176
|
+
const accesses = [];
|
|
177
|
+
|
|
178
|
+
const visit = (node) => {
|
|
179
|
+
if (ts.isImportDeclaration(node) && imports.some((entry) => entry.statement === node)) return;
|
|
180
|
+
if (ts.isIdentifier(node) && byNamespace.has(node.text) && !isPropertyName(node)) {
|
|
181
|
+
const parent = node.parent;
|
|
182
|
+
if (!ts.isPropertyAccessExpression(parent) || parent.expression !== node || !ts.isIdentifier(parent.name)) {
|
|
183
|
+
fail(file, node, source, `unsupported use of namespace ${node.text} (only \`${node.text}.Name\` reads can be rewritten)`);
|
|
184
|
+
}
|
|
185
|
+
// `ns.x` may sit inside a destructuring target like `{a: ns.x} = y` or
|
|
186
|
+
// `for ([ns.x] of y)`; climb out of the pattern so the write check sees
|
|
187
|
+
// the statement-level operator.
|
|
188
|
+
let pattern = parent;
|
|
189
|
+
let scope = parent.parent;
|
|
190
|
+
while (
|
|
191
|
+
ts.isObjectLiteralExpression(scope) || ts.isArrayLiteralExpression(scope)
|
|
192
|
+
|| ts.isPropertyAssignment(scope) || ts.isShorthandPropertyAssignment(scope)
|
|
193
|
+
|| ts.isSpreadElement(scope) || ts.isSpreadAssignment(scope) || ts.isBindingElement(scope)
|
|
194
|
+
) {
|
|
195
|
+
pattern = scope;
|
|
196
|
+
scope = scope.parent;
|
|
197
|
+
}
|
|
198
|
+
const isWrite = (ts.isBinaryExpression(scope) && scope.left === pattern
|
|
199
|
+
&& scope.operatorToken.kind >= ts.SyntaxKind.FirstAssignment
|
|
200
|
+
&& scope.operatorToken.kind <= ts.SyntaxKind.LastAssignment)
|
|
201
|
+
|| (ts.isDeleteExpression(scope) && scope.expression === pattern)
|
|
202
|
+
|| ((ts.isPrefixUnaryExpression(scope) || ts.isPostfixUnaryExpression(scope)) && scope.operand === pattern
|
|
203
|
+
&& (scope.operator === ts.SyntaxKind.PlusPlusToken || scope.operator === ts.SyntaxKind.MinusMinusToken))
|
|
204
|
+
|| ((ts.isForInStatement(scope) || ts.isForOfStatement(scope)) && scope.initializer === pattern);
|
|
205
|
+
if (isWrite) fail(file, node, source, `mutation of ${node.text}.${parent.name.text} cannot be rewritten`);
|
|
206
|
+
used.get(node.text).add(parent.name.text);
|
|
207
|
+
accesses.push(parent);
|
|
208
|
+
}
|
|
209
|
+
ts.forEachChild(node, visit);
|
|
210
|
+
};
|
|
211
|
+
visit(source);
|
|
212
|
+
|
|
213
|
+
const edits = [];
|
|
214
|
+
for (const { statement, namespace, barrel } of imports) {
|
|
215
|
+
const exported = exportsByBarrel.get(barrel);
|
|
216
|
+
const byModule = new Map();
|
|
217
|
+
for (const name of [...used.get(namespace)].sort()) {
|
|
218
|
+
const module = exported.get(name);
|
|
219
|
+
if (!module) fail(file, statement, source, `${namespace}.${name} is not exported by ${relative(dirname(file), barrel)}`);
|
|
220
|
+
const alias = `${namespace}_${name}`;
|
|
221
|
+
if (existing.has(alias)) fail(file, statement, source, `alias ${alias} already exists in this module`);
|
|
222
|
+
if (!byModule.has(module)) byModule.set(module, []);
|
|
223
|
+
byModule.get(module).push(name);
|
|
224
|
+
}
|
|
225
|
+
const replacement = [...byModule]
|
|
226
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
227
|
+
.map(([module, names]) => {
|
|
228
|
+
const specifiers = names.map((name) => `${name} as ${namespace}_${name}`).join(', ');
|
|
229
|
+
return `import { ${specifiers} } from ${JSON.stringify(specifierFor(file, module))};`;
|
|
230
|
+
})
|
|
231
|
+
.join(' ');
|
|
232
|
+
edits.push({ start: statement.getStart(source), end: statement.getEnd(), text: replacement });
|
|
233
|
+
}
|
|
234
|
+
for (const access of accesses) {
|
|
235
|
+
edits.push({ start: access.getStart(source), end: access.getEnd(), text: `${access.expression.text}_${access.name.text}` });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const original = source.getFullText();
|
|
239
|
+
let text = original;
|
|
240
|
+
for (const edit of edits.sort((a, b) => b.start - a.start)) {
|
|
241
|
+
text = text.slice(0, edit.start) + edit.text + text.slice(edit.end);
|
|
242
|
+
}
|
|
243
|
+
assertLayoutPreserved(file, original, text, imports.map(({ statement }) => source.getLineAndCharacterOfPosition(statement.getStart(source)).line));
|
|
244
|
+
return text;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Source maps stay valid only if every line other than a rewritten import
|
|
249
|
+
* line keeps its content length and position. `ns.Name` → `ns_Name` is
|
|
250
|
+
* length-neutral; import lines only exist at the top, above any mapping.
|
|
251
|
+
*/
|
|
252
|
+
function assertLayoutPreserved(file, before, after, importLines) {
|
|
253
|
+
const a = before.split('\n');
|
|
254
|
+
const b = after.split('\n');
|
|
255
|
+
if (a.length !== b.length) throw new UnbarrelError(`${file}: rewrite changed the line count (${a.length} → ${b.length})`);
|
|
256
|
+
const rewritten = new Set(importLines);
|
|
257
|
+
for (let line = 0; line < a.length; line += 1) {
|
|
258
|
+
if (!rewritten.has(line) && a[line].length !== b[line].length) {
|
|
259
|
+
throw new UnbarrelError(`${file}:${line + 1}: rewrite changed a column position`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Modules under `root` that import a model barrel as a namespace, as `path (namespace)`. */
|
|
265
|
+
export function remainingBarrelImports(root = ESM) {
|
|
266
|
+
root = resolve(root);
|
|
267
|
+
const barrels = barrelsIn(root);
|
|
268
|
+
return listModules(root).flatMap((file) =>
|
|
269
|
+
barrelImports(file, parse(file), barrels).map(({ namespace }) => `${relative(root, file).split(sep).join('/')} (${namespace})`),
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Rewrite every module under `root` in place. Returns the number of files changed. */
|
|
274
|
+
export function unbarrelImports(root = ESM) {
|
|
275
|
+
root = resolve(root);
|
|
276
|
+
const exportsByBarrel = new Map(barrelsIn(root).map((barrel) => [barrel, barrelExports(barrel)]));
|
|
277
|
+
const rewrites = [];
|
|
278
|
+
for (const file of listModules(root)) {
|
|
279
|
+
const text = rewriteFile(file, exportsByBarrel);
|
|
280
|
+
if (text !== undefined) rewrites.push([file, text]);
|
|
281
|
+
}
|
|
282
|
+
for (const [file, text] of rewrites) writeFileSync(file, text);
|
|
283
|
+
const remaining = remainingBarrelImports(root);
|
|
284
|
+
if (remaining.length > 0) throw new UnbarrelError(`barrel imports left after rewrite:\n${remaining.join('\n')}`);
|
|
285
|
+
return rewrites.length;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
|
289
|
+
try {
|
|
290
|
+
console.log(`unbarrel-imports: rewrote ${unbarrelImports()} files`);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
if (!(error instanceof UnbarrelError)) throw error;
|
|
293
|
+
console.error(`unbarrel-imports: ${error.message}`);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
}
|
|
296
|
+
}
|