soltag 0.0.2 → 0.0.3

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/LICENSE CHANGED
@@ -1,7 +1,5 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 morpho-org
4
-
5
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
4
  of this software and associated documentation files (the "Software"), to deal
7
5
  in the Software without restriction, including without limitation the rights
package/README.md CHANGED
@@ -1,35 +1,35 @@
1
1
  # soltag
2
2
 
3
- Inline Solidity in TypeScript. Write Solidity inside a tagged template literal, get real-time IDE type inference, and execute deployless reads via `eth_call` + `stateOverride`.
3
+ Inline Solidity in TypeScript. Write Solidity inside a tagged template literal, get a data object with typed `abi`, `bytecode()`, `deployedBytecode`, and a deterministic `address`.
4
4
 
5
5
  ```ts
6
6
  import { sol } from 'soltag';
7
7
 
8
- const contract = sol`
8
+ const lens = sol("Lens")`
9
9
  pragma solidity ^0.8.24;
10
10
  interface IERC20 { function balanceOf(address) external view returns (uint256); }
11
- library Lens {
12
- function userBalances(address[] memory tokens, address user)
13
- external view returns (uint256[] memory out)
11
+ contract Lens {
12
+ function getBalance(address token, address user)
13
+ external view returns (uint256)
14
14
  {
15
- out = new uint256[](tokens.length);
16
- for (uint256 i = 0; i < tokens.length; i++) {
17
- out[i] = IERC20(tokens[i]).balanceOf(user);
18
- }
15
+ return IERC20(token).balanceOf(user);
19
16
  }
20
17
  }
21
18
  `;
22
19
 
23
- const balances = await contract.call(client, 'userBalances', [[USDC, WETH], user]);
24
- // ^? bigint[] ^? autocompletes ^? typed args
20
+ lens.name; // "Lens" (typed as literal)
21
+ lens.abi; // precise, as-const ABI (via generated .d.ts)
22
+ lens.address; // `0x${string}` (deterministic, derived from deployedBytecode)
23
+ lens.deployedBytecode; // `0x${string}` (runtime bytecode)
24
+ lens.bytecode(); // `0x${string}` (creation bytecode)
25
25
  ```
26
26
 
27
27
  ## Features
28
28
 
29
- - **`sol` tagged template** — write Solidity inline, get a `SolContract` you can `.call()` against any RPC. Supports string interpolation for composing reusable fragments
30
- - **Real-time IDE support** — function name autocomplete, typed args, return type hover, inline Solidity diagnostics via a TypeScript Language Service Plugin (no codegen)
29
+ - **`sol("Name")` tagged template** — write Solidity inline, get a `InlineContract` with typed ABI, bytecode, and a deterministic address. Supports string interpolation for composing reusable fragments
30
+ - **Real-time IDE support** — inline Solidity diagnostics and contract-name validation via a TypeScript Language Service Plugin. ABI and `bytecode()` types are provided through generated `.d.ts` augmentation
31
31
  - **Build-time compilation** — bundler plugin (Vite, Rollup, esbuild, webpack) compiles Solidity at build time so `solc` (8MB WASM) never ships to production
32
- - **Deployless execution** — uses `eth_call` with `stateOverride` to run contract code without deploying
32
+ - **Data-oriented** — `InlineContract` is a plain data container. Use `abi` and `bytecode` with whatever execution library you prefer (viem, ethers, etc.)
33
33
 
34
34
  ## Install
35
35
 
@@ -55,14 +55,20 @@ pnpm add -D solc unplugin magic-string
55
55
 
56
56
  ### Bundler Plugin (recommended for apps)
57
57
 
58
- Compiles `sol` templates at build time — `solc` is only needed during the build, not at runtime.
58
+ Compiles `sol("Name")` templates at build time — `solc` is only needed during the build, not at runtime.
59
59
 
60
60
  ```ts
61
61
  // vite.config.ts
62
62
  import soltag from 'soltag/vite';
63
63
 
64
64
  export default defineConfig({
65
- plugins: [soltag()],
65
+ plugins: [
66
+ soltag({
67
+ solc: {
68
+ optimizer: { enabled: true, runs: 200 }
69
+ }
70
+ })
71
+ ],
66
72
  });
67
73
  ```
68
74
 
@@ -76,7 +82,7 @@ import soltag from 'soltag/webpack';
76
82
 
77
83
  ### TypeScript Plugin (IDE support)
78
84
 
79
- Add to your `tsconfig.json` for autocomplete, hover types, and inline Solidity diagnostics:
85
+ Add to your `tsconfig.json` for inline Solidity diagnostics and contract-name validation:
80
86
 
81
87
  ```json
82
88
  {
@@ -94,12 +100,8 @@ Add to your `tsconfig.json` for autocomplete, hover types, and inline Solidity d
94
100
 
95
101
  ```ts
96
102
  import { sol } from 'soltag';
97
- import { createPublicClient, http } from 'viem';
98
- import { mainnet } from 'viem/chains';
99
-
100
- const client = createPublicClient({ chain: mainnet, transport: http() });
101
103
 
102
- const contract = sol`
104
+ const math = sol("Math")`
103
105
  pragma solidity ^0.8.24;
104
106
  contract Math {
105
107
  function add(uint256 a, uint256 b) external pure returns (uint256) {
@@ -108,30 +110,68 @@ const contract = sol`
108
110
  }
109
111
  `;
110
112
 
111
- const result = await contract.call(client, 'add', [1n, 2n]);
112
- // result === 3n
113
+ math.name; // "Math"
114
+ math.abi; // readonly [{ type: "function", name: "add", ... }]
115
+ math.bytecode(); // creation bytecode
116
+ math.deployedBytecode; // runtime bytecode
117
+ math.address; // deterministic address derived from deployedBytecode
113
118
  ```
114
119
 
115
- ### Reading on-chain state
120
+ ### Constructor arguments
121
+
122
+ For contracts with constructors, `bytecode()` accepts typed arguments:
116
123
 
117
124
  ```ts
118
- const contract = sol`
125
+ const token = sol("MyToken")`
119
126
  pragma solidity ^0.8.24;
120
- interface IERC20 {
121
- function balanceOf(address) external view returns (uint256);
122
- function decimals() external view returns (uint8);
127
+ contract MyToken {
128
+ uint256 public supply;
129
+ constructor(uint256 _supply) {
130
+ supply = _supply;
131
+ }
123
132
  }
124
- library Lens {
133
+ `;
134
+
135
+ token.bytecode(1000n); // creation bytecode + ABI-encoded constructor args
136
+ ```
137
+
138
+ ### Using with viem
139
+
140
+ `InlineContract` is a data container — use its properties with any execution library. Here's an example with viem's `eth_call` + `stateOverride` for deployless reads:
141
+
142
+ ```ts
143
+ import { createPublicClient, http, decodeFunctionResult, encodeFunctionData } from 'viem';
144
+ import { mainnet } from 'viem/chains';
145
+ import { sol } from 'soltag';
146
+
147
+ const client = createPublicClient({ chain: mainnet, transport: http() });
148
+
149
+ const lens = sol("Lens")`
150
+ pragma solidity ^0.8.24;
151
+ interface IERC20 { function balanceOf(address) external view returns (uint256); }
152
+ contract Lens {
125
153
  function getBalance(address token, address user)
126
- external view returns (uint256 balance, uint8 decimals)
154
+ external view returns (uint256)
127
155
  {
128
- balance = IERC20(token).balanceOf(user);
129
- decimals = IERC20(token).decimals();
156
+ return IERC20(token).balanceOf(user);
130
157
  }
131
158
  }
132
159
  `;
133
160
 
134
- const [balance, decimals] = await contract.call(client, 'getBalance', [USDC, user]);
161
+ const data = encodeFunctionData({
162
+ abi: lens.abi,
163
+ functionName: 'getBalance',
164
+ args: [USDC, user],
165
+ });
166
+
167
+ const result = await client.call({
168
+ to: lens.address,
169
+ data,
170
+ stateOverrides: [{
171
+ address: lens.address,
172
+ code: lens.deployedBytecode,
173
+ }],
174
+ });
135
175
  ```
136
176
 
137
177
  ### Composing with fragments
@@ -146,7 +186,7 @@ const IERC20 = `
146
186
  }
147
187
  `;
148
188
 
149
- const balanceLens = sol`
189
+ const balanceLens = sol("BalanceLens")`
150
190
  pragma solidity ^0.8.24;
151
191
  ${IERC20}
152
192
  contract BalanceLens {
@@ -158,18 +198,6 @@ const balanceLens = sol`
158
198
  }
159
199
  }
160
200
  `;
161
-
162
- const allowanceLens = sol`
163
- pragma solidity ^0.8.24;
164
- ${IERC20}
165
- contract AllowanceLens {
166
- function getAllowance(address token, address owner, address spender)
167
- external view returns (uint256)
168
- {
169
- return IERC20(token).allowance(owner, spender);
170
- }
171
- }
172
- `;
173
201
  ```
174
202
 
175
203
  The bundler plugin resolves `const` string interpolations at build time, so these templates are still compiled ahead of time. Interpolations that can't be statically resolved (e.g. variables from function calls) are left for runtime compilation.
@@ -179,13 +207,13 @@ The bundler plugin resolves `const` string interpolations at build time, so thes
179
207
  For environments where you want full control over the compilation step:
180
208
 
181
209
  ```ts
182
- import { SolContract } from 'soltag';
210
+ import { InlineContract } from 'soltag';
183
211
 
184
- const contract = SolContract.fromArtifacts({
212
+ const contract = InlineContract.fromArtifacts("MyContract", {
185
213
  MyContract: {
186
214
  abi: [/* ... */],
187
215
  deployedBytecode: '0x...',
188
- initBytecode: '0x...',
216
+ bytecode: '0x...',
189
217
  },
190
218
  });
191
219
  ```
@@ -194,48 +222,66 @@ const contract = SolContract.fromArtifacts({
194
222
 
195
223
  ### Runtime path (scripts, testing)
196
224
 
197
- 1. `sol` tag captures the Solidity source string
198
- 2. On first `.call()`, compiles with `solc-js` (lazy-loaded) and caches the result
199
- 3. Derives a deterministic address from the source hash
200
- 4. Executes via `eth_call` with `stateOverride` — the contract bytecode is injected at the derived address without deploying
201
- 5. Decodes the return value via viem's ABI decoder
225
+ 1. `sol("Name")` captures the Solidity source string and contract name
226
+ 2. On first property access, compiles with `solc-js` (lazy-loaded) and caches the result
227
+ 3. Exposes `abi`, `bytecode()`, and `deployedBytecode` for the named contract
228
+ 4. Derives a deterministic `address` from `keccak256(deployedBytecode)`
202
229
 
203
230
  ### Build-time path (apps with bundler plugin)
204
231
 
205
- 1. The bundler plugin parses each file's AST to find `sol` tagged templates
232
+ 1. The bundler plugin parses each file's AST to find `sol("Name")` tagged templates
206
233
  2. For templates with interpolations, resolves `const` string values statically
207
234
  3. Compiles the resolved Solidity with `solc-js` during the build
208
- 4. Replaces `` sol`...` `` with `SolContract.fromArtifacts({...})` containing the pre-compiled ABI and bytecode
209
- 5. At runtime, no compilation happens — only ABI encoding, `eth_call`, and decoding
235
+ 4. Replaces `` sol("Name")`...` `` with `InlineContract.fromArtifacts("Name", {...})` containing the pre-compiled ABI and bytecode
236
+ 5. At runtime, no compilation happens — property access returns pre-compiled data directly
210
237
 
211
238
  ### IDE path (TypeScript Language Service Plugin)
212
239
 
213
240
  1. The TS plugin runs in `tsserver` (your editor's TypeScript process)
214
- 2. It finds `sol` tagged templates, compiles them with solc-js, and extracts the ABI
215
- 3. Provides function name completions for `.call()`, hover types showing Solidity-to-TypeScript mappings, and inline diagnostics for Solidity compilation errors
241
+ 2. It finds `sol("Name")` tagged templates, compiles them with solc-js, and extracts the ABI
242
+ 3. Generates `.soltag/types.d.ts` with module augmentation that narrows `abi` to precise "as const" types and adds typed `bytecode()` overloads per contract
243
+ 4. Reports inline Solidity compilation errors and warns if the contract name doesn't match any contract in the source
244
+
245
+ ## Immutables Caveat
246
+
247
+ Solidity `immutable` variables are assigned in the constructor and baked into the runtime bytecode during deployment. The `deployedBytecode` returned by solc (and exposed by `InlineContract`) contains **placeholder zeros** in immutable slots — the real values are only filled in when the constructor actually runs on-chain.
248
+
249
+ This means **`deployedBytecode` is unsuitable for `stateOverride` injection** when the contract uses immutable variables. The zeroed slots will cause the contract to behave incorrectly.
250
+
251
+ If your contract uses immutables, deploy it normally using `bytecode(…constructorArgs)` instead of injecting `deployedBytecode` via `stateOverride`. Note that `bytecode()` returns _creation_ bytecode (the code that runs the constructor and returns the final runtime code), not runtime bytecode with constructor args spliced in — there is no way to produce correct runtime bytecode with immutables without actually executing the constructor.
216
252
 
217
253
  ## API
218
254
 
219
255
  ### `sol`
220
256
 
221
257
  ```ts
222
- function sol(strings: TemplateStringsArray, ...values: string[]): SolContract;
258
+ function sol<TName extends string>(name: TName):
259
+ (strings: TemplateStringsArray, ...values: string[]) => InlineContract<TName>;
223
260
  ```
224
261
 
225
- Tagged template literal. Accepts string interpolations for composing Solidity from reusable fragments.
262
+ Factory that returns a tagged template function. The `name` must match a contract in the Solidity source.
226
263
 
227
- ### `SolContract`
264
+ ### `InlineContract<TName>`
228
265
 
229
266
  ```ts
230
- class SolContract {
267
+ class InlineContract<TName extends string = string> {
231
268
  // Create from pre-compiled artifacts (used by bundler plugin)
232
- static fromArtifacts(artifacts: CompilationResult, sourceHash?: Hex): SolContract;
269
+ static fromArtifacts<T extends string>(name: T, artifacts: CompilationResult): InlineContract<T>;
270
+
271
+ // The contract name (typed as a string literal)
272
+ get name(): TName;
273
+
274
+ // The contract's ABI (narrowed to precise type via generated .d.ts)
275
+ get abi(): Abi;
276
+
277
+ // Runtime bytecode as emitted by solc (see Immutables Caveat)
278
+ get deployedBytecode(): Hex;
233
279
 
234
- // Merged ABI across all contracts in the source
235
- readonly abi: Abi;
280
+ // Deterministic address derived from keccak256(deployedBytecode)
281
+ get address(): Hex;
236
282
 
237
- // Execute a read-only call via stateOverride
238
- call(client: PublicClient, functionName: string, args?: readonly unknown[]): Promise<unknown>;
283
+ // Creation bytecode, optionally with ABI-encoded constructor args appended
284
+ bytecode(...args: unknown[]): Hex;
239
285
  }
240
286
  ```
241
287
 
@@ -0,0 +1,351 @@
1
+ // src/bundler/unplugin.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import MagicString from "magic-string";
5
+ import ts from "typescript";
6
+ import { createUnplugin } from "unplugin";
7
+
8
+ // src/ast-utils.ts
9
+ function isSolTag(ts2, tag) {
10
+ if (ts2.isCallExpression(tag) && ts2.isIdentifier(tag.expression) && tag.expression.text === "sol" && tag.arguments.length === 1 && ts2.isStringLiteral(tag.arguments[0])) {
11
+ return { contractName: tag.arguments[0].text };
12
+ }
13
+ return false;
14
+ }
15
+ function resolveStringExpression(ts2, node, sourceFile) {
16
+ if (ts2.isStringLiteral(node)) return node.text;
17
+ if (ts2.isNoSubstitutionTemplateLiteral(node)) return node.text;
18
+ if (ts2.isTemplateExpression(node)) {
19
+ let result = node.head.text;
20
+ for (const span of node.templateSpans) {
21
+ const resolved = resolveStringExpression(ts2, span.expression, sourceFile);
22
+ if (resolved === void 0) return void 0;
23
+ result += resolved + span.literal.text;
24
+ }
25
+ return result;
26
+ }
27
+ if (ts2.isIdentifier(node)) {
28
+ return resolveIdentifierToString(ts2, node, sourceFile);
29
+ }
30
+ if (ts2.isBinaryExpression(node) && node.operatorToken.kind === ts2.SyntaxKind.PlusToken) {
31
+ const left = resolveStringExpression(ts2, node.left, sourceFile);
32
+ const right = resolveStringExpression(ts2, node.right, sourceFile);
33
+ if (left !== void 0 && right !== void 0) return left + right;
34
+ return void 0;
35
+ }
36
+ return void 0;
37
+ }
38
+ function resolveIdentifierToString(ts2, identifier, sourceFile) {
39
+ const name = identifier.text;
40
+ for (const statement of sourceFile.statements) {
41
+ if (!ts2.isVariableStatement(statement)) continue;
42
+ if (!(statement.declarationList.flags & ts2.NodeFlags.Const)) continue;
43
+ for (const decl of statement.declarationList.declarations) {
44
+ if (ts2.isIdentifier(decl.name) && decl.name.text === name && decl.initializer) {
45
+ return resolveStringExpression(ts2, decl.initializer, sourceFile);
46
+ }
47
+ }
48
+ }
49
+ return void 0;
50
+ }
51
+ function extractTemplateSource(ts2, template, sourceFile) {
52
+ if (ts2.isNoSubstitutionTemplateLiteral(template)) {
53
+ return template.text;
54
+ }
55
+ let result = template.head.text;
56
+ for (const span of template.templateSpans) {
57
+ const resolved = resolveStringExpression(ts2, span.expression, sourceFile);
58
+ if (resolved === void 0) return void 0;
59
+ result += resolved + span.literal.text;
60
+ }
61
+ return result;
62
+ }
63
+
64
+ // src/codegen.ts
65
+ var SOLTAG_DIR = ".soltag";
66
+ var SOLTAG_TYPES_FILE = "types.d.ts";
67
+ function solidityTypeToTs(param) {
68
+ const t = param.type;
69
+ if (t === "address") return "`0x${string}`";
70
+ if (t === "bool") return "boolean";
71
+ if (t === "string") return "string";
72
+ if (t === "bytes" || t.match(/^bytes\d+$/)) return "`0x${string}`";
73
+ if (t.match(/^u?int\d*$/)) return "bigint";
74
+ if (t.endsWith("[]")) {
75
+ const inner = { ...param, type: t.slice(0, -2) };
76
+ return `${solidityTypeToTs(inner)}[]`;
77
+ }
78
+ const fixedArray = t.match(/^(.+)\[(\d+)\]$/);
79
+ if (fixedArray) {
80
+ const inner = { ...param, type: fixedArray[1] };
81
+ return `${solidityTypeToTs(inner)}[]`;
82
+ }
83
+ if (t === "tuple" && param.components) {
84
+ const fields = param.components.map((c) => `${c.name}: ${solidityTypeToTs(c)}`).join("; ");
85
+ return `{ ${fields} }`;
86
+ }
87
+ return "unknown";
88
+ }
89
+ function jsonToConstType(value) {
90
+ if (value === null || value === void 0) return "null";
91
+ if (typeof value === "string") return JSON.stringify(value);
92
+ if (typeof value === "number") return String(value);
93
+ if (typeof value === "boolean") return String(value);
94
+ if (Array.isArray(value)) {
95
+ if (value.length === 0) return "readonly []";
96
+ return `readonly [${value.map(jsonToConstType).join(", ")}]`;
97
+ }
98
+ if (typeof value === "object") {
99
+ const entries = Object.entries(value);
100
+ if (entries.length === 0) return "{}";
101
+ const fields = entries.map(([k, v]) => `readonly ${k}: ${jsonToConstType(v)}`);
102
+ return `{ ${fields.join("; ")} }`;
103
+ }
104
+ return "unknown";
105
+ }
106
+ function generateDeclarationContent(entries) {
107
+ if (entries.length === 0) return { content: "", duplicates: [] };
108
+ const byName = /* @__PURE__ */ new Map();
109
+ for (const entry of entries) {
110
+ const existing = byName.get(entry.contractName);
111
+ if (existing) {
112
+ existing.push(entry);
113
+ } else {
114
+ byName.set(entry.contractName, [entry]);
115
+ }
116
+ }
117
+ const duplicates = [];
118
+ const unique = [];
119
+ for (const [name, group] of byName) {
120
+ unique.push(group[0]);
121
+ if (group.length > 1) {
122
+ const fingerprints = new Set(
123
+ group.map((e) => JSON.stringify({ constructorInputs: e.constructorInputs, abi: e.abi }))
124
+ );
125
+ if (fingerprints.size > 1) {
126
+ duplicates.push(name);
127
+ }
128
+ }
129
+ }
130
+ const abiMapEntries = [];
131
+ const overloads = [];
132
+ for (const entry of unique) {
133
+ abiMapEntries.push(` ${JSON.stringify(entry.contractName)}: ${jsonToConstType(entry.abi)};`);
134
+ const params = entry.constructorInputs.map((p, i) => {
135
+ const name = p.name || `arg${i}`;
136
+ return `${name}: ${solidityTypeToTs(p)}`;
137
+ });
138
+ overloads.push(
139
+ ` bytecode(this: InlineContract<${JSON.stringify(entry.contractName)}>${params.length > 0 ? `, ${params.join(", ")}` : ""}): \`0x\${string}\`;`
140
+ );
141
+ }
142
+ if (unique.length === 0) return { content: "", duplicates };
143
+ const content = `export {}
144
+ declare module "soltag" {
145
+ interface InlineContractAbiMap {
146
+ ${abiMapEntries.join("\n")}
147
+ }
148
+ interface InlineContract<TName extends string> {
149
+ ${overloads.join("\n")}
150
+ }
151
+ }
152
+ `;
153
+ return { content, duplicates };
154
+ }
155
+
156
+ // src/runtime/compiler.ts
157
+ import { createRequire } from "module";
158
+ import { keccak256, toHex } from "viem";
159
+
160
+ // src/solc.ts
161
+ function buildSolcInput(source, options) {
162
+ return {
163
+ language: "Solidity",
164
+ sources: {
165
+ "inline.sol": { content: source }
166
+ },
167
+ settings: {
168
+ optimizer: {
169
+ enabled: options?.optimizer?.enabled ?? true,
170
+ runs: options?.optimizer?.runs ?? 1
171
+ },
172
+ outputSelection: {
173
+ "*": {
174
+ "*": ["abi", "evm.bytecode.object", "evm.deployedBytecode.object"]
175
+ }
176
+ }
177
+ }
178
+ };
179
+ }
180
+
181
+ // src/runtime/compiler.ts
182
+ var require2 = createRequire(import.meta.url);
183
+ var solcInstance;
184
+ function getSolc() {
185
+ if (!solcInstance) {
186
+ try {
187
+ solcInstance = require2("solc");
188
+ } catch {
189
+ throw new Error(
190
+ "solc is not installed. Install it (`pnpm add solc`) for runtime compilation, or use the soltag bundler plugin for build-time compilation."
191
+ );
192
+ }
193
+ }
194
+ return solcInstance;
195
+ }
196
+ var SolCompilationError = class extends Error {
197
+ constructor(errors) {
198
+ const formatted = errors.map((e) => `${e.severity}: ${e.message}`).join("\n");
199
+ super(`Solidity compilation failed:
200
+ ${formatted}`);
201
+ this.errors = errors;
202
+ this.name = "SolCompilationError";
203
+ }
204
+ };
205
+ var compilationCache = /* @__PURE__ */ new Map();
206
+ function hashSource(source, options) {
207
+ return keccak256(toHex(source + JSON.stringify(options ?? {})));
208
+ }
209
+ function compile(source, options) {
210
+ const hash = hashSource(source, options);
211
+ const cached = compilationCache.get(hash);
212
+ if (cached) return cached;
213
+ const solc = getSolc();
214
+ const input = buildSolcInput(source, options);
215
+ const rawOutput = solc.compile(JSON.stringify(input));
216
+ const output = JSON.parse(rawOutput);
217
+ const diagnostics = toDiagnostics(output.errors);
218
+ const errors = diagnostics.filter((d) => d.severity === "error");
219
+ if (errors.length > 0) {
220
+ throw new SolCompilationError(errors);
221
+ }
222
+ const result = {};
223
+ if (output.contracts) {
224
+ for (const [, fileContracts] of Object.entries(output.contracts)) {
225
+ for (const [contractName, contractOutput] of Object.entries(fileContracts)) {
226
+ result[contractName] = {
227
+ abi: contractOutput.abi,
228
+ deployedBytecode: `0x${contractOutput.evm.deployedBytecode.object}`,
229
+ bytecode: `0x${contractOutput.evm.bytecode.object}`
230
+ };
231
+ }
232
+ }
233
+ }
234
+ compilationCache.set(hash, result);
235
+ return result;
236
+ }
237
+ function toDiagnostics(errors) {
238
+ return (errors ?? []).map((e) => ({
239
+ severity: e.severity,
240
+ message: e.message,
241
+ formattedMessage: e.formattedMessage,
242
+ sourceLocation: e.sourceLocation
243
+ }));
244
+ }
245
+
246
+ // src/bundler/unplugin.ts
247
+ function getConstructorInputs(abi) {
248
+ const ctor = abi.find((item) => item.type === "constructor");
249
+ if (!ctor) return [];
250
+ return ctor.inputs ?? [];
251
+ }
252
+ function transformSolTemplates(code, id, namedEntries, options) {
253
+ if (!/\bsol\s*\(\s*["'][^"']+["']\s*\)/.test(code)) return void 0;
254
+ const sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
255
+ const s = new MagicString(code);
256
+ let hasReplacements = false;
257
+ function visit(node) {
258
+ if (ts.isTaggedTemplateExpression(node)) {
259
+ const solTag = isSolTag(ts, node.tag);
260
+ if (solTag) {
261
+ const contractName = solTag.contractName;
262
+ const soliditySource = extractTemplateSource(ts, node.template, sourceFile);
263
+ if (soliditySource === void 0) {
264
+ return;
265
+ }
266
+ const artifacts = compile(soliditySource, options?.solc);
267
+ if (namedEntries != null) {
268
+ const contractArtifact = artifacts[contractName];
269
+ const constructorInputs = contractArtifact ? getConstructorInputs(contractArtifact.abi) : [];
270
+ const abi = contractArtifact ? contractArtifact.abi : [];
271
+ namedEntries.set(`${contractName}\0${soliditySource}`, {
272
+ contractName,
273
+ constructorInputs,
274
+ abi
275
+ });
276
+ }
277
+ const replacement = `__InlineContract.fromArtifacts(${JSON.stringify(contractName)}, ${JSON.stringify(artifacts)})`;
278
+ s.overwrite(node.getStart(sourceFile), node.getEnd(), replacement);
279
+ hasReplacements = true;
280
+ return;
281
+ }
282
+ }
283
+ ts.forEachChild(node, visit);
284
+ }
285
+ visit(sourceFile);
286
+ if (!hasReplacements) return void 0;
287
+ s.prepend('import { InlineContract as __InlineContract } from "soltag";\n');
288
+ return {
289
+ code: s.toString(),
290
+ map: s.generateMap({ source: id, hires: true })
291
+ };
292
+ }
293
+ var unplugin = createUnplugin((options) => {
294
+ const include = options?.include ?? [".ts", ".tsx", ".mts", ".cts"];
295
+ const exclude = options?.exclude ?? [/node_modules/];
296
+ const namedEntries = /* @__PURE__ */ new Map();
297
+ let rootDir;
298
+ return {
299
+ name: "soltag",
300
+ enforce: "pre",
301
+ vite: {
302
+ configResolved(config) {
303
+ rootDir = config.root;
304
+ }
305
+ },
306
+ buildStart() {
307
+ namedEntries.clear();
308
+ },
309
+ transform: {
310
+ filter: {
311
+ id: {
312
+ include: include.map((ext) => new RegExp(`${ext.replace(".", "\\.")}$`)),
313
+ exclude
314
+ }
315
+ },
316
+ handler(code, id) {
317
+ if (!rootDir) {
318
+ rootDir = process.cwd();
319
+ }
320
+ return transformSolTemplates(code, id, namedEntries, options);
321
+ }
322
+ },
323
+ buildEnd() {
324
+ if (!rootDir || namedEntries.size === 0) return;
325
+ const entries = Array.from(namedEntries.values());
326
+ const { content } = generateDeclarationContent(entries);
327
+ if (content === "") return;
328
+ const typesDir = path.join(rootDir, SOLTAG_DIR);
329
+ const typesFile = path.join(typesDir, SOLTAG_TYPES_FILE);
330
+ if (!fs.existsSync(typesDir)) {
331
+ fs.mkdirSync(typesDir, { recursive: true });
332
+ }
333
+ let existing;
334
+ try {
335
+ existing = fs.readFileSync(typesFile, "utf-8");
336
+ } catch {
337
+ }
338
+ if (existing !== content) {
339
+ fs.writeFileSync(typesFile, content, "utf-8");
340
+ }
341
+ }
342
+ };
343
+ });
344
+ var unplugin_default = unplugin;
345
+
346
+ export {
347
+ transformSolTemplates,
348
+ unplugin,
349
+ unplugin_default
350
+ };
351
+ //# sourceMappingURL=chunk-YTNI7QSL.js.map