soltag 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 morpho-org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,248 @@
1
+ # soltag
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`.
4
+
5
+ ```ts
6
+ import { sol } from 'soltag';
7
+
8
+ const contract = sol`
9
+ pragma solidity ^0.8.24;
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)
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
+ }
19
+ }
20
+ }
21
+ `;
22
+
23
+ const balances = await contract.call(client, 'userBalances', [[USDC, WETH], user]);
24
+ // ^? bigint[] ^? autocompletes ^? typed args
25
+ ```
26
+
27
+ ## Features
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)
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
33
+
34
+ ## Install
35
+
36
+ ```sh
37
+ pnpm add soltag viem
38
+ ```
39
+
40
+ For **runtime compilation** (scripts, REPLs, testing), also install `solc`:
41
+
42
+ ```sh
43
+ pnpm add solc
44
+ ```
45
+
46
+ For the **bundler plugin** (recommended for apps), install `solc` as a dev dependency along with `unplugin` and `magic-string`:
47
+
48
+ ```sh
49
+ pnpm add -D solc unplugin magic-string
50
+ ```
51
+
52
+ > **Note on `pragma solidity`:** The pragma in your Solidity source is a compatibility constraint checked by solc at compile time — it doesn't select a compiler version. As long as your installed `solc` version satisfies the pragma range (e.g. solc 0.8.28 satisfies `^0.8.24`), compilation proceeds. If it doesn't, solc will reject it with an error.
53
+
54
+ ## Setup
55
+
56
+ ### Bundler Plugin (recommended for apps)
57
+
58
+ Compiles `sol` templates at build time — `solc` is only needed during the build, not at runtime.
59
+
60
+ ```ts
61
+ // vite.config.ts
62
+ import soltag from 'soltag/vite';
63
+
64
+ export default defineConfig({
65
+ plugins: [soltag()],
66
+ });
67
+ ```
68
+
69
+ Also available for other bundlers:
70
+
71
+ ```ts
72
+ import soltag from 'soltag/rollup';
73
+ import soltag from 'soltag/esbuild';
74
+ import soltag from 'soltag/webpack';
75
+ ```
76
+
77
+ ### TypeScript Plugin (IDE support)
78
+
79
+ Add to your `tsconfig.json` for autocomplete, hover types, and inline Solidity diagnostics:
80
+
81
+ ```json
82
+ {
83
+ "compilerOptions": {
84
+ "plugins": [{ "name": "soltag/plugin" }]
85
+ }
86
+ }
87
+ ```
88
+
89
+ > VS Code users: make sure your workspace is using the TypeScript version from `node_modules` (not the built-in one). Open a `.ts` file, click the TypeScript version in the bottom status bar, and select "Use Workspace Version".
90
+
91
+ ## Usage
92
+
93
+ ### Basic
94
+
95
+ ```ts
96
+ 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
+
102
+ const contract = sol`
103
+ pragma solidity ^0.8.24;
104
+ contract Math {
105
+ function add(uint256 a, uint256 b) external pure returns (uint256) {
106
+ return a + b;
107
+ }
108
+ }
109
+ `;
110
+
111
+ const result = await contract.call(client, 'add', [1n, 2n]);
112
+ // result === 3n
113
+ ```
114
+
115
+ ### Reading on-chain state
116
+
117
+ ```ts
118
+ const contract = sol`
119
+ pragma solidity ^0.8.24;
120
+ interface IERC20 {
121
+ function balanceOf(address) external view returns (uint256);
122
+ function decimals() external view returns (uint8);
123
+ }
124
+ library Lens {
125
+ function getBalance(address token, address user)
126
+ external view returns (uint256 balance, uint8 decimals)
127
+ {
128
+ balance = IERC20(token).balanceOf(user);
129
+ decimals = IERC20(token).decimals();
130
+ }
131
+ }
132
+ `;
133
+
134
+ const [balance, decimals] = await contract.call(client, 'getBalance', [USDC, user]);
135
+ ```
136
+
137
+ ### Composing with fragments
138
+
139
+ The `sol` tag supports string interpolation, so you can define reusable Solidity fragments and compose them:
140
+
141
+ ```ts
142
+ const IERC20 = `
143
+ interface IERC20 {
144
+ function balanceOf(address) external view returns (uint256);
145
+ function decimals() external view returns (uint8);
146
+ }
147
+ `;
148
+
149
+ const balanceLens = sol`
150
+ pragma solidity ^0.8.24;
151
+ ${IERC20}
152
+ contract BalanceLens {
153
+ function getBalance(address token, address user)
154
+ external view returns (uint256 balance, uint8 decimals)
155
+ {
156
+ balance = IERC20(token).balanceOf(user);
157
+ decimals = IERC20(token).decimals();
158
+ }
159
+ }
160
+ `;
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
+ ```
174
+
175
+ 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.
176
+
177
+ ### Pre-compiled artifacts
178
+
179
+ For environments where you want full control over the compilation step:
180
+
181
+ ```ts
182
+ import { SolContract } from 'soltag';
183
+
184
+ const contract = SolContract.fromArtifacts({
185
+ MyContract: {
186
+ abi: [/* ... */],
187
+ deployedBytecode: '0x...',
188
+ initBytecode: '0x...',
189
+ },
190
+ });
191
+ ```
192
+
193
+ ## How It Works
194
+
195
+ ### Runtime path (scripts, testing)
196
+
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
202
+
203
+ ### Build-time path (apps with bundler plugin)
204
+
205
+ 1. The bundler plugin parses each file's AST to find `sol` tagged templates
206
+ 2. For templates with interpolations, resolves `const` string values statically
207
+ 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
210
+
211
+ ### IDE path (TypeScript Language Service Plugin)
212
+
213
+ 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
216
+
217
+ ## API
218
+
219
+ ### `sol`
220
+
221
+ ```ts
222
+ function sol(strings: TemplateStringsArray, ...values: string[]): SolContract;
223
+ ```
224
+
225
+ Tagged template literal. Accepts string interpolations for composing Solidity from reusable fragments.
226
+
227
+ ### `SolContract`
228
+
229
+ ```ts
230
+ class SolContract {
231
+ // Create from pre-compiled artifacts (used by bundler plugin)
232
+ static fromArtifacts(artifacts: CompilationResult, sourceHash?: Hex): SolContract;
233
+
234
+ // Merged ABI across all contracts in the source
235
+ readonly abi: Abi;
236
+
237
+ // Execute a read-only call via stateOverride
238
+ call(client: PublicClient, functionName: string, args?: readonly unknown[]): Promise<unknown>;
239
+ }
240
+ ```
241
+
242
+ ### `SolCompilationError`
243
+
244
+ Thrown when Solidity compilation fails. Contains a `.errors` array of `SolcDiagnostic` objects with severity, message, and source location.
245
+
246
+ ## License
247
+
248
+ MIT
@@ -0,0 +1,192 @@
1
+ // src/build/unplugin.ts
2
+ import MagicString from "magic-string";
3
+ import ts from "typescript";
4
+ import { createUnplugin } from "unplugin";
5
+
6
+ // src/runtime/compiler.ts
7
+ import { createRequire } from "module";
8
+ import { keccak256, toHex } from "viem";
9
+
10
+ // src/solc.ts
11
+ function buildSolcInput(source) {
12
+ return {
13
+ language: "Solidity",
14
+ sources: {
15
+ "inline.sol": { content: source }
16
+ },
17
+ settings: {
18
+ optimizer: { enabled: true, runs: 1 },
19
+ outputSelection: {
20
+ "*": {
21
+ "*": ["abi", "evm.bytecode.object", "evm.deployedBytecode.object"]
22
+ }
23
+ }
24
+ }
25
+ };
26
+ }
27
+
28
+ // src/runtime/compiler.ts
29
+ var require2 = createRequire(import.meta.url);
30
+ var solcInstance;
31
+ function getSolc() {
32
+ if (!solcInstance) {
33
+ try {
34
+ solcInstance = require2("solc");
35
+ } catch {
36
+ throw new Error(
37
+ "solc is not installed. Install it (`pnpm add solc`) for runtime compilation, or use the soltag bundler plugin for build-time compilation."
38
+ );
39
+ }
40
+ }
41
+ return solcInstance;
42
+ }
43
+ var SolCompilationError = class extends Error {
44
+ constructor(errors) {
45
+ const formatted = errors.map((e) => `${e.severity}: ${e.message}`).join("\n");
46
+ super(`Solidity compilation failed:
47
+ ${formatted}`);
48
+ this.errors = errors;
49
+ this.name = "SolCompilationError";
50
+ }
51
+ };
52
+ var compilationCache = /* @__PURE__ */ new Map();
53
+ function hashSource(source) {
54
+ return keccak256(toHex(source));
55
+ }
56
+ function compile(source) {
57
+ const hash = hashSource(source);
58
+ const cached = compilationCache.get(hash);
59
+ if (cached) return cached;
60
+ const solc = getSolc();
61
+ const input = buildSolcInput(source);
62
+ const rawOutput = solc.compile(JSON.stringify(input));
63
+ const output = JSON.parse(rawOutput);
64
+ const diagnostics = toDiagnostics(output.errors);
65
+ const errors = diagnostics.filter((d) => d.severity === "error");
66
+ if (errors.length > 0) {
67
+ throw new SolCompilationError(errors);
68
+ }
69
+ const result = {};
70
+ if (output.contracts) {
71
+ for (const [, fileContracts] of Object.entries(output.contracts)) {
72
+ for (const [contractName, contractOutput] of Object.entries(fileContracts)) {
73
+ result[contractName] = {
74
+ abi: contractOutput.abi,
75
+ deployedBytecode: `0x${contractOutput.evm.deployedBytecode.object}`,
76
+ initBytecode: `0x${contractOutput.evm.bytecode.object}`
77
+ };
78
+ }
79
+ }
80
+ }
81
+ compilationCache.set(hash, result);
82
+ return result;
83
+ }
84
+ function toDiagnostics(errors) {
85
+ return (errors ?? []).map((e) => ({
86
+ severity: e.severity,
87
+ message: e.message,
88
+ formattedMessage: e.formattedMessage,
89
+ sourceLocation: e.sourceLocation
90
+ }));
91
+ }
92
+
93
+ // src/build/unplugin.ts
94
+ function resolveStringExpression(node, sourceFile) {
95
+ if (ts.isStringLiteral(node)) return node.text;
96
+ if (ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
97
+ if (ts.isTemplateExpression(node)) {
98
+ let result = node.head.text;
99
+ for (const span of node.templateSpans) {
100
+ const resolved = resolveStringExpression(span.expression, sourceFile);
101
+ if (resolved === void 0) return void 0;
102
+ result += resolved + span.literal.text;
103
+ }
104
+ return result;
105
+ }
106
+ if (ts.isIdentifier(node)) {
107
+ return resolveIdentifierToString(node, sourceFile);
108
+ }
109
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {
110
+ const left = resolveStringExpression(node.left, sourceFile);
111
+ const right = resolveStringExpression(node.right, sourceFile);
112
+ if (left !== void 0 && right !== void 0) return left + right;
113
+ return void 0;
114
+ }
115
+ return void 0;
116
+ }
117
+ function resolveIdentifierToString(identifier, sourceFile) {
118
+ const name = identifier.text;
119
+ for (const statement of sourceFile.statements) {
120
+ if (!ts.isVariableStatement(statement)) continue;
121
+ if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;
122
+ for (const decl of statement.declarationList.declarations) {
123
+ if (ts.isIdentifier(decl.name) && decl.name.text === name && decl.initializer) {
124
+ return resolveStringExpression(decl.initializer, sourceFile);
125
+ }
126
+ }
127
+ }
128
+ return void 0;
129
+ }
130
+ function extractTemplateSource(template, sourceFile) {
131
+ if (ts.isNoSubstitutionTemplateLiteral(template)) {
132
+ return template.text;
133
+ }
134
+ let result = template.head.text;
135
+ for (const span of template.templateSpans) {
136
+ const resolved = resolveStringExpression(span.expression, sourceFile);
137
+ if (resolved === void 0) return void 0;
138
+ result += resolved + span.literal.text;
139
+ }
140
+ return result;
141
+ }
142
+ function transformSolTemplates(code, id) {
143
+ if (!code.includes("sol`") && !code.includes("sol `")) return void 0;
144
+ const sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);
145
+ const s = new MagicString(code);
146
+ let hasReplacements = false;
147
+ function visit(node) {
148
+ if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === "sol") {
149
+ const soliditySource = extractTemplateSource(node.template, sourceFile);
150
+ if (soliditySource === void 0) {
151
+ return;
152
+ }
153
+ const artifacts = compile(soliditySource);
154
+ const sourceHash = hashSource(soliditySource);
155
+ const replacement = `__SolContract.fromArtifacts(${JSON.stringify(artifacts)}, "${sourceHash}")`;
156
+ s.overwrite(node.getStart(sourceFile), node.getEnd(), replacement);
157
+ hasReplacements = true;
158
+ return;
159
+ }
160
+ ts.forEachChild(node, visit);
161
+ }
162
+ visit(sourceFile);
163
+ if (!hasReplacements) return void 0;
164
+ s.prepend('import { SolContract as __SolContract } from "soltag";\n');
165
+ return {
166
+ code: s.toString(),
167
+ map: s.generateMap({ source: id, hires: true })
168
+ };
169
+ }
170
+ var unplugin = createUnplugin((options) => {
171
+ const include = options?.include ?? [".ts", ".tsx", ".mts", ".cts"];
172
+ const exclude = options?.exclude ?? [/node_modules/];
173
+ return {
174
+ name: "soltag",
175
+ enforce: "pre",
176
+ transformInclude(id) {
177
+ if (exclude.some((e) => e.test(id))) return false;
178
+ return include.some((ext) => id.endsWith(ext));
179
+ },
180
+ transform(code, id) {
181
+ return transformSolTemplates(code, id);
182
+ }
183
+ };
184
+ });
185
+ var unplugin_default = unplugin;
186
+
187
+ export {
188
+ transformSolTemplates,
189
+ unplugin,
190
+ unplugin_default
191
+ };
192
+ //# sourceMappingURL=chunk-LNEBK5MP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/build/unplugin.ts","../src/runtime/compiler.ts","../src/solc.ts"],"sourcesContent":["import MagicString from \"magic-string\";\nimport ts from \"typescript\";\nimport { createUnplugin } from \"unplugin\";\n\nimport { compile, hashSource } from \"../runtime/compiler.js\";\n\nexport interface SoltagPluginOptions {\n /** Extra file extensions to include. Defaults to ['.ts', '.tsx', '.mts', '.cts'] */\n include?: string[];\n /** Patterns to exclude. Defaults to [/node_modules/] */\n exclude?: RegExp[];\n}\n\n/**\n * Try to resolve a TS expression to a string constant at build time.\n * Returns the resolved string, or undefined if the expression can't be statically resolved.\n */\nfunction resolveStringExpression(node: ts.Expression, sourceFile: ts.SourceFile): string | undefined {\n if (ts.isStringLiteral(node)) return node.text;\n\n if (ts.isNoSubstitutionTemplateLiteral(node)) return node.text;\n\n if (ts.isTemplateExpression(node)) {\n let result = node.head.text;\n for (const span of node.templateSpans) {\n const resolved = resolveStringExpression(span.expression, sourceFile);\n if (resolved === undefined) return undefined;\n result += resolved + span.literal.text;\n }\n return result;\n }\n\n if (ts.isIdentifier(node)) {\n return resolveIdentifierToString(node, sourceFile);\n }\n\n // String concatenation with +\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = resolveStringExpression(node.left, sourceFile);\n const right = resolveStringExpression(node.right, sourceFile);\n if (left !== undefined && right !== undefined) return left + right;\n return undefined;\n }\n\n return undefined;\n}\n\n/**\n * Find a const declaration for an identifier and resolve its string value.\n */\nfunction resolveIdentifierToString(identifier: ts.Identifier, sourceFile: ts.SourceFile): string | undefined {\n const name = identifier.text;\n\n for (const statement of sourceFile.statements) {\n if (!ts.isVariableStatement(statement)) continue;\n if (!(statement.declarationList.flags & ts.NodeFlags.Const)) continue;\n\n for (const decl of statement.declarationList.declarations) {\n if (ts.isIdentifier(decl.name) && decl.name.text === name && decl.initializer) {\n return resolveStringExpression(decl.initializer, sourceFile);\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Extract the full Solidity source from a tagged template, resolving interpolations.\n * Returns undefined if any interpolation can't be statically resolved.\n */\nfunction extractTemplateSource(template: ts.TemplateLiteral, sourceFile: ts.SourceFile): string | undefined {\n if (ts.isNoSubstitutionTemplateLiteral(template)) {\n return template.text;\n }\n\n let result = template.head.text;\n for (const span of template.templateSpans) {\n const resolved = resolveStringExpression(span.expression, sourceFile);\n if (resolved === undefined) return undefined;\n result += resolved + span.literal.text;\n }\n return result;\n}\n\n/**\n * Core transform logic, exported for testing.\n */\nexport function transformSolTemplates(\n code: string,\n id: string,\n): { code: string; map: ReturnType<MagicString[\"generateMap\"]> } | undefined {\n if (!code.includes(\"sol`\") && !code.includes(\"sol `\")) return undefined;\n\n const sourceFile = ts.createSourceFile(id, code, ts.ScriptTarget.Latest, true);\n const s = new MagicString(code);\n let hasReplacements = false;\n\n function visit(node: ts.Node) {\n if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && node.tag.text === \"sol\") {\n const soliditySource = extractTemplateSource(node.template, sourceFile);\n if (soliditySource === undefined) {\n // Can't resolve at build time — leave for runtime\n return;\n }\n\n const artifacts = compile(soliditySource);\n const sourceHash = hashSource(soliditySource);\n\n const replacement = `__SolContract.fromArtifacts(${JSON.stringify(artifacts)}, \"${sourceHash}\")`;\n s.overwrite(node.getStart(sourceFile), node.getEnd(), replacement);\n hasReplacements = true;\n return; // Don't visit children\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n\n if (!hasReplacements) return undefined;\n\n s.prepend('import { SolContract as __SolContract } from \"soltag\";\\n');\n\n return {\n code: s.toString(),\n map: s.generateMap({ source: id, hires: true }),\n };\n}\n\nexport const unplugin = createUnplugin((options?: SoltagPluginOptions) => {\n const include = options?.include ?? [\".ts\", \".tsx\", \".mts\", \".cts\"];\n const exclude = options?.exclude ?? [/node_modules/];\n\n return {\n name: \"soltag\",\n enforce: \"pre\" as const,\n\n transformInclude(id: string) {\n if (exclude.some((e) => e.test(id))) return false;\n return include.some((ext) => id.endsWith(ext));\n },\n\n transform(code: string, id: string) {\n return transformSolTemplates(code, id);\n },\n };\n});\n\nexport default unplugin;\n","import { createRequire } from \"node:module\";\n\nimport { type Abi, type Hex, keccak256, toHex } from \"viem\";\n\nimport { buildSolcInput, type SolcError, type SolcModule, type SolcStandardOutput } from \"../solc.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet solcInstance: SolcModule | undefined;\n\nfunction getSolc(): SolcModule {\n if (!solcInstance) {\n try {\n solcInstance = require(\"solc\") as SolcModule;\n } catch {\n throw new Error(\n \"solc is not installed. Install it (`pnpm add solc`) for runtime compilation, \" +\n \"or use the soltag bundler plugin for build-time compilation.\",\n );\n }\n }\n return solcInstance;\n}\n\nexport type { SolcAbiItem, SolcAbiParam } from \"../solc.js\";\n\nexport interface CompiledContract {\n abi: Abi;\n /** Runtime bytecode (what lives at the contract address). Used with stateOverride. */\n deployedBytecode: Hex;\n /** Init bytecode (constructor + deployment code). Used for actual deployment. */\n initBytecode: Hex;\n}\n\nexport type CompilationResult = Record<string, CompiledContract>;\n\nexport interface SolcDiagnostic {\n severity: \"error\" | \"warning\";\n message: string;\n formattedMessage: string;\n sourceLocation?: {\n file: string;\n start: number;\n end: number;\n };\n}\n\nexport class SolCompilationError extends Error {\n constructor(public readonly errors: SolcDiagnostic[]) {\n const formatted = errors.map((e) => `${e.severity}: ${e.message}`).join(\"\\n\");\n super(`Solidity compilation failed:\\n${formatted}`);\n this.name = \"SolCompilationError\";\n }\n}\n\n// Cache compiled results by source hash\nconst compilationCache = new Map<string, CompilationResult>();\n\nexport function hashSource(source: string): Hex {\n return keccak256(toHex(source));\n}\n\nexport function compile(source: string): CompilationResult {\n const hash = hashSource(source);\n const cached = compilationCache.get(hash);\n if (cached) return cached;\n\n const solc = getSolc();\n const input = buildSolcInput(source);\n const rawOutput = solc.compile(JSON.stringify(input));\n const output = JSON.parse(rawOutput) as SolcStandardOutput;\n\n const diagnostics = toDiagnostics(output.errors);\n const errors = diagnostics.filter((d) => d.severity === \"error\");\n if (errors.length > 0) {\n throw new SolCompilationError(errors);\n }\n\n const result: CompilationResult = {};\n\n if (output.contracts) {\n for (const [, fileContracts] of Object.entries(output.contracts)) {\n for (const [contractName, contractOutput] of Object.entries(fileContracts)) {\n result[contractName] = {\n abi: contractOutput.abi as Abi,\n deployedBytecode: `0x${contractOutput.evm.deployedBytecode.object}` as Hex,\n initBytecode: `0x${contractOutput.evm.bytecode.object}` as Hex,\n };\n }\n }\n }\n\n compilationCache.set(hash, result);\n return result;\n}\n\nfunction toDiagnostics(errors: SolcError[] | undefined): SolcDiagnostic[] {\n return (errors ?? []).map((e) => ({\n severity: e.severity as \"error\" | \"warning\",\n message: e.message,\n formattedMessage: e.formattedMessage,\n sourceLocation: e.sourceLocation,\n }));\n}\n","/**\n * Shared solc-js types and helpers used by both the runtime compiler\n * and the LS plugin cache.\n */\n\nexport interface SolcModule {\n compile(input: string): string;\n}\n\n/**\n * Build the standard JSON input object for solc.\n */\nexport function buildSolcInput(source: string) {\n return {\n language: \"Solidity\" as const,\n sources: {\n \"inline.sol\": { content: source },\n },\n settings: {\n optimizer: { enabled: true, runs: 1 },\n outputSelection: {\n \"*\": {\n \"*\": [\"abi\", \"evm.bytecode.object\", \"evm.deployedBytecode.object\"],\n },\n },\n },\n };\n}\n\n// --- solc standard output types ---\n\nexport interface SolcStandardOutput {\n contracts?: Record<string, Record<string, SolcContractOutput>>;\n errors?: SolcError[];\n}\n\nexport interface SolcContractOutput {\n abi: SolcAbiItem[];\n evm: {\n bytecode: { object: string };\n deployedBytecode: { object: string };\n };\n}\n\nexport interface SolcAbiItem {\n type: string;\n name?: string;\n inputs?: SolcAbiParam[];\n outputs?: SolcAbiParam[];\n stateMutability?: string;\n}\n\nexport interface SolcAbiParam {\n name: string;\n type: string;\n components?: SolcAbiParam[];\n internalType?: string;\n}\n\nexport interface SolcError {\n severity: string;\n message: string;\n formattedMessage: string;\n sourceLocation?: {\n file: string;\n start: number;\n end: number;\n };\n}\n"],"mappings":"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","names":["require"]}
@@ -0,0 +1,7 @@
1
+ import * as unplugin from 'unplugin';
2
+ import { SoltagPluginOptions } from './unplugin.js';
3
+ import 'magic-string';
4
+
5
+ declare const _default: (options?: SoltagPluginOptions | undefined) => unplugin.EsbuildPlugin;
6
+
7
+ export { _default as default };
@@ -0,0 +1,10 @@
1
+ import {
2
+ unplugin
3
+ } from "./chunk-LNEBK5MP.js";
4
+
5
+ // src/build/esbuild.ts
6
+ var esbuild_default = unplugin.esbuild;
7
+ export {
8
+ esbuild_default as default
9
+ };
10
+ //# sourceMappingURL=esbuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/build/esbuild.ts"],"sourcesContent":["import { unplugin } from \"./unplugin.js\";\nexport default unplugin.esbuild;\n"],"mappings":";;;;;AACA,IAAO,kBAAQ,SAAS;","names":[]}
@@ -0,0 +1,95 @@
1
+ import { Abi, Hex, PublicClient } from 'viem';
2
+
3
+ interface SolcAbiItem {
4
+ type: string;
5
+ name?: string;
6
+ inputs?: SolcAbiParam[];
7
+ outputs?: SolcAbiParam[];
8
+ stateMutability?: string;
9
+ }
10
+ interface SolcAbiParam {
11
+ name: string;
12
+ type: string;
13
+ components?: SolcAbiParam[];
14
+ internalType?: string;
15
+ }
16
+
17
+ interface CompiledContract {
18
+ abi: Abi;
19
+ /** Runtime bytecode (what lives at the contract address). Used with stateOverride. */
20
+ deployedBytecode: Hex;
21
+ /** Init bytecode (constructor + deployment code). Used for actual deployment. */
22
+ initBytecode: Hex;
23
+ }
24
+ type CompilationResult = Record<string, CompiledContract>;
25
+ interface SolcDiagnostic {
26
+ severity: "error" | "warning";
27
+ message: string;
28
+ formattedMessage: string;
29
+ sourceLocation?: {
30
+ file: string;
31
+ start: number;
32
+ end: number;
33
+ };
34
+ }
35
+ declare class SolCompilationError extends Error {
36
+ readonly errors: SolcDiagnostic[];
37
+ constructor(errors: SolcDiagnostic[]);
38
+ }
39
+
40
+ declare class SolContract {
41
+ private _source;
42
+ private _compiled;
43
+ private _address;
44
+ private _abi;
45
+ constructor(source: string);
46
+ /**
47
+ * Create a SolContract from pre-compiled artifacts.
48
+ * Used by the bundler plugin to bypass runtime solc compilation.
49
+ *
50
+ * @param artifacts - Pre-compiled contract artifacts (ABI + bytecode per contract name)
51
+ * @param sourceHash - keccak256 of the original Solidity source, for deterministic address derivation
52
+ */
53
+ static fromArtifacts(artifacts: CompilationResult, sourceHash?: Hex): SolContract;
54
+ private ensureCompiled;
55
+ private getAddress;
56
+ get abi(): Abi;
57
+ call(client: PublicClient, functionName: string, args?: readonly unknown[]): Promise<unknown>;
58
+ }
59
+
60
+ /**
61
+ * Tagged template literal for inline Solidity.
62
+ *
63
+ * Usage:
64
+ * ```ts
65
+ * const contract = sol`
66
+ * pragma solidity ^0.8.24;
67
+ * contract Greeter {
68
+ * function greet() external pure returns (string memory) {
69
+ * return "hello";
70
+ * }
71
+ * }
72
+ * `;
73
+ * ```
74
+ *
75
+ * String interpolation is supported for composing Solidity from reusable fragments:
76
+ * ```ts
77
+ * const IERC20 = `
78
+ * interface IERC20 {
79
+ * function balanceOf(address) external view returns (uint256);
80
+ * }
81
+ * `;
82
+ *
83
+ * const contract = sol`
84
+ * ${IERC20}
85
+ * contract Lens {
86
+ * function getBalance(address token, address user) external view returns (uint256) {
87
+ * return IERC20(token).balanceOf(user);
88
+ * }
89
+ * }
90
+ * `;
91
+ * ```
92
+ */
93
+ declare function sol(strings: TemplateStringsArray, ...values: string[]): SolContract;
94
+
95
+ export { type CompilationResult, type CompiledContract, SolCompilationError, SolContract, type SolcAbiItem, type SolcAbiParam, type SolcDiagnostic, sol };