From d76ebd71258a3854f7d776d3cbd11239264928dd Mon Sep 17 00:00:00 2001 From: Omri Katz <9701896+omridevk@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:17:17 +0300 Subject: [PATCH 1/3] fix(extension-compiler): react dist entries never hot-serve as solid-compiled src Co-Authored-By: Claude Fable 5 --- .changeset/react-dist-hotserve.md | 5 +++++ packages/extension-compiler/src/conciv-src.ts | 1 + packages/extension-compiler/test/conciv-src.it.test.ts | 8 ++++++++ .../test/fixtures/conciv-src/scoped/dist/react/index.js | 1 + .../fixtures/conciv-src/scoped/dist/react/mascot-root.js | 1 + .../test/fixtures/conciv-src/scoped/src/react/index.ts | 1 + .../fixtures/conciv-src/scoped/src/react/mascot-root.tsx | 1 + 7 files changed, 18 insertions(+) create mode 100644 .changeset/react-dist-hotserve.md create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx diff --git a/.changeset/react-dist-hotserve.md b/.changeset/react-dist-hotserve.md new file mode 100644 index 000000000..79889cf2e --- /dev/null +++ b/.changeset/react-dist-hotserve.md @@ -0,0 +1,5 @@ +--- +'@conciv/extension-compiler': patch +--- + +React entry points of `@conciv/*` packages now always resolve to their built `dist` files in dev. The vite dev hot-serve remaps a workspace `dist` entry to its `src` sibling and Solid-compiles the TSX it finds there, which turned `@conciv/mascot/react` into Solid output inside a React host and crashed server rendering with `Comp is not a function`. Any dist stem under `react/` is now left on dist, where it needs no transform; the `.jsx` Solid-condition mapping is unchanged. diff --git a/packages/extension-compiler/src/conciv-src.ts b/packages/extension-compiler/src/conciv-src.ts index bd602fda6..2006e5ea2 100644 --- a/packages/extension-compiler/src/conciv-src.ts +++ b/packages/extension-compiler/src/conciv-src.ts @@ -34,6 +34,7 @@ export function concivSrcEntry(resolvedPath: string): string | null { const marker = resolvedPath.lastIndexOf('/dist/') if (marker === -1) return null const stem = resolvedPath.slice(marker + '/dist/'.length, -extension.length) + if (stem.startsWith('react/')) return null const srcStem = `${resolvedPath.slice(0, marker)}/src/${stem}` return [`${srcStem}.tsx`, `${srcStem}.ts`].find((candidate) => existsSync(candidate)) ?? null } diff --git a/packages/extension-compiler/test/conciv-src.it.test.ts b/packages/extension-compiler/test/conciv-src.it.test.ts index 0ff6f0944..f2e7078eb 100644 --- a/packages/extension-compiler/test/conciv-src.it.test.ts +++ b/packages/extension-compiler/test/conciv-src.it.test.ts @@ -45,6 +45,14 @@ describe('concivSrcEntry', () => { expect(concivSrcEntry(fixture('scoped/dist/solid/index.jsx'))).toBe(fixture('scoped/src/solid/index.ts')) }) + it('keeps a react dist entry on dist even though a ts source sibling exists', () => { + expect(concivSrcEntry(fixture('scoped/dist/react/index.js'))).toBeNull() + }) + + it('keeps a react dist entry on dist even though a tsx source sibling exists', () => { + expect(concivSrcEntry(fixture('scoped/dist/react/mascot-root.js'))).toBeNull() + }) + it('returns null when no source sibling exists', () => { expect(concivSrcEntry(fixture('scoped/dist/nope.js'))).toBeNull() }) diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js new file mode 100644 index 000000000..336ce12bb --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js @@ -0,0 +1 @@ +export {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js new file mode 100644 index 000000000..336ce12bb --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js @@ -0,0 +1 @@ +export {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts new file mode 100644 index 000000000..5903dc5ea --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts @@ -0,0 +1 @@ +export const Mascot = () => null diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx new file mode 100644 index 000000000..310bde074 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx @@ -0,0 +1 @@ +export const MascotRoot = () => null From 31ae29737d28b6de6da3cf0f915f81af91e83ba9 Mon Sep 17 00:00:00 2001 From: Omri Katz <9701896+omridevk@users.noreply.github.com> Date: Mon, 17 Aug 2026 02:25:24 +0300 Subject: [PATCH 2/3] fix(extension-compiler,mascot): derive hot-serve non-Solid classification from tsconfig JSX, not folder names The vite dev hot-serve remap (dist entry -> src sibling, Solid-compiled) used to key off a `react/` folder-name convention, which is not a real signal: a subtree's JSX compilation mode is declared by its nearest tsconfig, not its directory name. concivSrcEntry now walks up to the found source file's nearest tsconfig.json (following its extends chain) and classifies non-Solid whenever the effective jsxImportSource is set to something other than solid-js, or jsx is react-jsx/ react-jsxdev without a solid-js jsxImportSource; everything else (explicit jsxImportSource: solid-js, or no JSX config anywhere in the chain) keeps remapping. @conciv/mascot's React wrapper carried its JSX config in a sibling tsconfig.react.json at the package root, which the nearest-tsconfig directory walk can't discover from src/react/. Relocated to src/react/tsconfig.json so the declaration lives with the code it governs; tsdown.react.config.ts and the package's typecheck script now point at the new path. Co-Authored-By: Claude Fable 5 --- .changeset/react-dist-hotserve.md | 4 +- packages/extension-compiler/src/conciv-src.ts | 81 ++++++++++++++++++- .../test/conciv-src.it.test.ts | 24 +++++- .../dist/react => plain/dist}/index.js | 0 .../fixtures/conciv-src/plain/package.json | 4 + .../fixtures/conciv-src/plain/src/index.ts | 1 + .../index.js} | 0 .../conciv-src/scoped/dist/inherited/index.js | 1 + .../conciv-src/scoped/dist/wrapper/index.js | 1 + .../scoped/dist/wrapper/mascot-root.js | 1 + .../scoped/src/explicit-react/index.tsx | 1 + .../scoped/src/explicit-react/tsconfig.json | 5 ++ .../conciv-src/scoped/src/inherited/index.tsx | 1 + .../scoped/src/inherited/tsconfig.json | 3 + .../scoped/src/{react => wrapper}/index.ts | 0 .../src/{react => wrapper}/mascot-root.tsx | 0 .../scoped/src/wrapper/tsconfig.json | 5 ++ .../fixtures/conciv-src/scoped/tsconfig.json | 6 ++ packages/mascot/package.json | 2 +- packages/mascot/src/react/tsconfig.json | 11 +++ packages/mascot/tsconfig.react.json | 11 --- packages/mascot/tsdown.react.config.ts | 2 +- 22 files changed, 144 insertions(+), 20 deletions(-) rename packages/extension-compiler/test/fixtures/conciv-src/{scoped/dist/react => plain/dist}/index.js (100%) create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/plain/package.json create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/plain/src/index.ts rename packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/{react/mascot-root.js => explicit-react/index.js} (100%) create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/inherited/index.js create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/index.js create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/mascot-root.js create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/index.tsx create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/tsconfig.json create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/index.tsx create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/tsconfig.json rename packages/extension-compiler/test/fixtures/conciv-src/scoped/src/{react => wrapper}/index.ts (100%) rename packages/extension-compiler/test/fixtures/conciv-src/scoped/src/{react => wrapper}/mascot-root.tsx (100%) create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/tsconfig.json create mode 100644 packages/extension-compiler/test/fixtures/conciv-src/scoped/tsconfig.json create mode 100644 packages/mascot/src/react/tsconfig.json delete mode 100644 packages/mascot/tsconfig.react.json diff --git a/.changeset/react-dist-hotserve.md b/.changeset/react-dist-hotserve.md index 79889cf2e..235fa838f 100644 --- a/.changeset/react-dist-hotserve.md +++ b/.changeset/react-dist-hotserve.md @@ -2,4 +2,6 @@ '@conciv/extension-compiler': patch --- -React entry points of `@conciv/*` packages now always resolve to their built `dist` files in dev. The vite dev hot-serve remaps a workspace `dist` entry to its `src` sibling and Solid-compiles the TSX it finds there, which turned `@conciv/mascot/react` into Solid output inside a React host and crashed server rendering with `Comp is not a function`. Any dist stem under `react/` is now left on dist, where it needs no transform; the `.jsx` Solid-condition mapping is unchanged. +The vite dev hot-serve remaps a workspace `dist` entry to its `src` sibling and Solid-compiles the TSX it finds there. That remap used to key off a `react/` folder-name convention, which turned `@conciv/mascot/react` into Solid output inside a React host and crashed server rendering with `Comp is not a function`. The decision is now derived from the found source file's nearest `tsconfig.json` (following its `extends` chain): a subtree whose effective `compilerOptions.jsxImportSource` is set to something other than `solid-js`, or whose `compilerOptions.jsx` is `react-jsx`/`react-jsxdev` without a `solid-js` `jsxImportSource`, is classified non-Solid and stays on `dist`. Everything else — an explicit `jsxImportSource: "solid-js"`, or no JSX config in the chain at all (pure-TS subtrees) — keeps the existing remap-to-`src` behavior. + +`@conciv/mascot`'s React wrapper subtree carried its JSX config in a sibling file (`tsconfig.react.json` at the package root) rather than in a tsconfig local to `src/react/`, which the nearest-tsconfig directory walk can't discover. It has been relocated to `src/react/tsconfig.json` so the declaration lives with the code it governs; `tsdown.react.config.ts` and the package's `typecheck` script now point at the new path. diff --git a/packages/extension-compiler/src/conciv-src.ts b/packages/extension-compiler/src/conciv-src.ts index 2006e5ea2..4516dad82 100644 --- a/packages/extension-compiler/src/conciv-src.ts +++ b/packages/extension-compiler/src/conciv-src.ts @@ -27,6 +27,81 @@ function packageNameFor(dir: string): string | null { const isConcivName = (name: string) => name.startsWith('@conciv/') +type JsxConfig = { + jsx: string | null + jsxImportSource: string | null +} + +type RawTsconfig = { + jsx: unknown + jsxImportSource: unknown + extends: unknown +} + +function parseTsconfig(path: string): RawTsconfig | null { + try { + const parsed: unknown = JSON.parse(readFileSync(path, 'utf8')) + if (typeof parsed !== 'object' || parsed === null) return null + const record = parsed as Record + const rawCompilerOptions = record.compilerOptions + const compilerOptions = + typeof rawCompilerOptions === 'object' && rawCompilerOptions !== null + ? (rawCompilerOptions as Record) + : {} + return {jsx: compilerOptions.jsx, jsxImportSource: compilerOptions.jsxImportSource, extends: record.extends} + } catch { + return null + } +} + +function resolveExtendsPath(fromPath: string, extendsValue: string): string | null { + if (!extendsValue.startsWith('.')) return null + const joined = join(dirname(fromPath), extendsValue) + return joined.endsWith('.json') ? joined : `${joined}.json` +} + +function resolveJsxConfig(path: string, visited: Set): JsxConfig { + if (visited.has(path)) return {jsx: null, jsxImportSource: null} + visited.add(path) + const raw = parseTsconfig(path) + if (raw === null) return {jsx: null, jsxImportSource: null} + const ownJsx = typeof raw.jsx === 'string' ? raw.jsx : null + const ownJsxImportSource = typeof raw.jsxImportSource === 'string' ? raw.jsxImportSource : null + if (typeof raw.extends !== 'string') return {jsx: ownJsx, jsxImportSource: ownJsxImportSource} + const extendsPath = resolveExtendsPath(path, raw.extends) + if (extendsPath === null) return {jsx: ownJsx, jsxImportSource: ownJsxImportSource} + const parentConfig = resolveJsxConfig(extendsPath, visited) + return { + jsx: ownJsx ?? parentConfig.jsx, + jsxImportSource: ownJsxImportSource ?? parentConfig.jsxImportSource, + } +} + +const tsconfigCache = new Map() + +function jsxConfigFor(dir: string): JsxConfig | null { + const cached = tsconfigCache.get(dir) + if (cached !== undefined) return cached + const ownTsconfig = join(dir, 'tsconfig.json') + const parent = dirname(dir) + const resolved = existsSync(ownTsconfig) + ? resolveJsxConfig(ownTsconfig, new Set()) + : parent === dir + ? null + : jsxConfigFor(parent) + tsconfigCache.set(dir, resolved) + return resolved +} + +function isNonSolidJsx(config: JsxConfig | null): boolean { + if (config === null) return false + if (config.jsxImportSource !== null && config.jsxImportSource !== 'solid-js') return true + if ((config.jsx === 'react-jsx' || config.jsx === 'react-jsxdev') && config.jsxImportSource !== 'solid-js') { + return true + } + return false +} + export function concivSrcEntry(resolvedPath: string): string | null { if (resolvedPath.includes('node_modules')) return null const extension = ['.jsx', '.js'].find((candidate) => resolvedPath.endsWith(candidate)) @@ -34,9 +109,11 @@ export function concivSrcEntry(resolvedPath: string): string | null { const marker = resolvedPath.lastIndexOf('/dist/') if (marker === -1) return null const stem = resolvedPath.slice(marker + '/dist/'.length, -extension.length) - if (stem.startsWith('react/')) return null const srcStem = `${resolvedPath.slice(0, marker)}/src/${stem}` - return [`${srcStem}.tsx`, `${srcStem}.ts`].find((candidate) => existsSync(candidate)) ?? null + const srcCandidate = [`${srcStem}.tsx`, `${srcStem}.ts`].find((candidate) => existsSync(candidate)) ?? null + if (srcCandidate === null) return null + if (isNonSolidJsx(jsxConfigFor(dirname(srcCandidate)))) return null + return srcCandidate } export function isConcivSrcTsx(id: string): boolean { diff --git a/packages/extension-compiler/test/conciv-src.it.test.ts b/packages/extension-compiler/test/conciv-src.it.test.ts index f2e7078eb..c3578e98b 100644 --- a/packages/extension-compiler/test/conciv-src.it.test.ts +++ b/packages/extension-compiler/test/conciv-src.it.test.ts @@ -45,12 +45,28 @@ describe('concivSrcEntry', () => { expect(concivSrcEntry(fixture('scoped/dist/solid/index.jsx'))).toBe(fixture('scoped/src/solid/index.ts')) }) - it('keeps a react dist entry on dist even though a ts source sibling exists', () => { - expect(concivSrcEntry(fixture('scoped/dist/react/index.js'))).toBeNull() + it('keeps a react-jsx subtree on dist even though a ts source sibling exists, regardless of folder name', () => { + expect(concivSrcEntry(fixture('scoped/dist/wrapper/index.js'))).toBeNull() }) - it('keeps a react dist entry on dist even though a tsx source sibling exists', () => { - expect(concivSrcEntry(fixture('scoped/dist/react/mascot-root.js'))).toBeNull() + it('keeps a react-jsx subtree on dist even though a tsx source sibling exists, regardless of folder name', () => { + expect(concivSrcEntry(fixture('scoped/dist/wrapper/mascot-root.js'))).toBeNull() + }) + + it('remaps the package root to src even when a sibling subtree carries its own react-jsx tsconfig', () => { + expect(concivSrcEntry(fixture('scoped/dist/index.js'))).toBe(fixture('scoped/src/index.tsx')) + }) + + it('keeps a dist entry on dist when its own tsconfig sets an explicit non-solid jsxImportSource', () => { + expect(concivSrcEntry(fixture('scoped/dist/explicit-react/index.js'))).toBeNull() + }) + + it('remaps a dist entry with no tsconfig of its own and no jsx anywhere in the chain (ts-only package)', () => { + expect(concivSrcEntry(fixture('plain/dist/index.js'))).toBe(fixture('plain/src/index.ts')) + }) + + it('remaps a dist entry whose own tsconfig is empty and inherits jsxImportSource solid-js via extends', () => { + expect(concivSrcEntry(fixture('scoped/dist/inherited/index.js'))).toBe(fixture('scoped/src/inherited/index.tsx')) }) it('returns null when no source sibling exists', () => { diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js b/packages/extension-compiler/test/fixtures/conciv-src/plain/dist/index.js similarity index 100% rename from packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/index.js rename to packages/extension-compiler/test/fixtures/conciv-src/plain/dist/index.js diff --git a/packages/extension-compiler/test/fixtures/conciv-src/plain/package.json b/packages/extension-compiler/test/fixtures/conciv-src/plain/package.json new file mode 100644 index 000000000..ba48380fd --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/plain/package.json @@ -0,0 +1,4 @@ +{ + "name": "@conciv/fixture-plain", + "type": "module" +} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/plain/src/index.ts b/packages/extension-compiler/test/fixtures/conciv-src/plain/src/index.ts new file mode 100644 index 000000000..28b31c7e1 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/plain/src/index.ts @@ -0,0 +1 @@ +export const plain = {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/explicit-react/index.js similarity index 100% rename from packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/react/mascot-root.js rename to packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/explicit-react/index.js diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/inherited/index.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/inherited/index.js new file mode 100644 index 000000000..336ce12bb --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/inherited/index.js @@ -0,0 +1 @@ +export {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/index.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/index.js new file mode 100644 index 000000000..336ce12bb --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/index.js @@ -0,0 +1 @@ +export {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/mascot-root.js b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/mascot-root.js new file mode 100644 index 000000000..336ce12bb --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/dist/wrapper/mascot-root.js @@ -0,0 +1 @@ +export {} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/index.tsx b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/index.tsx new file mode 100644 index 000000000..46ba2b4c8 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/index.tsx @@ -0,0 +1 @@ +export const ExplicitReact = () => null diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/tsconfig.json b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/tsconfig.json new file mode 100644 index 000000000..4f9190dd9 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/explicit-react/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsxImportSource": "react" + } +} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/index.tsx b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/index.tsx new file mode 100644 index 000000000..53e9efd9a --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/index.tsx @@ -0,0 +1 @@ +export const Inherited = () =>
ok
diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/tsconfig.json b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/tsconfig.json new file mode 100644 index 000000000..4082f16a5 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/inherited/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/index.ts similarity index 100% rename from packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/index.ts rename to packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/index.ts diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/mascot-root.tsx similarity index 100% rename from packages/extension-compiler/test/fixtures/conciv-src/scoped/src/react/mascot-root.tsx rename to packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/mascot-root.tsx diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/tsconfig.json b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/tsconfig.json new file mode 100644 index 000000000..a224293f4 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/src/wrapper/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "jsx": "react-jsx" + } +} diff --git a/packages/extension-compiler/test/fixtures/conciv-src/scoped/tsconfig.json b/packages/extension-compiler/test/fixtures/conciv-src/scoped/tsconfig.json new file mode 100644 index 000000000..f33507ab2 --- /dev/null +++ b/packages/extension-compiler/test/fixtures/conciv-src/scoped/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "jsxImportSource": "solid-js" + } +} diff --git a/packages/mascot/package.json b/packages/mascot/package.json index b1e2b05e9..3e19b61a5 100644 --- a/packages/mascot/package.json +++ b/packages/mascot/package.json @@ -105,7 +105,7 @@ }, "scripts": { "build": "tsdown && tsdown --config tsdown.solid-source.config.ts && tsdown --config tsdown.react.config.ts", - "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.react.json --noEmit", + "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p src/react/tsconfig.json --noEmit", "lint": "oxlint", "test": "vitest run --passWithNoTests && playwright test", "publint": "publint", diff --git a/packages/mascot/src/react/tsconfig.json b/packages/mascot/src/react/tsconfig.json new file mode 100644 index 000000000..b57d3c459 --- /dev/null +++ b/packages/mascot/src/react/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": "../..", + "noEmit": true, + "lib": ["ES2024", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "types": ["node"] + }, + "include": ["**/*.ts", "**/*.tsx", "../../tests/browser/react-wrapper.browser.test.tsx"] +} diff --git a/packages/mascot/tsconfig.react.json b/packages/mascot/tsconfig.react.json deleted file mode 100644 index 007692810..000000000 --- a/packages/mascot/tsconfig.react.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "rootDir": ".", - "noEmit": true, - "lib": ["ES2024", "DOM", "DOM.Iterable"], - "jsx": "react-jsx", - "types": ["node"] - }, - "include": ["src/react/**/*.ts", "src/react/**/*.tsx", "tests/browser/react-wrapper.browser.test.tsx"] -} diff --git a/packages/mascot/tsdown.react.config.ts b/packages/mascot/tsdown.react.config.ts index 585c68d58..e93b7bd6e 100644 --- a/packages/mascot/tsdown.react.config.ts +++ b/packages/mascot/tsdown.react.config.ts @@ -8,6 +8,6 @@ export default defineConfig({ unbundle: true, dts: true, clean: false, - tsconfig: 'tsconfig.react.json', + tsconfig: 'src/react/tsconfig.json', external: ['react', /^react\//, /^react-dom/, /^\.\.\//], }) From 81db783389dc5edea678e027cf3e89003318c8d4 Mon Sep 17 00:00:00 2001 From: Omri Katz <9701896+omridevk@users.noreply.github.com> Date: Mon, 17 Aug 2026 02:34:09 +0300 Subject: [PATCH 3/3] refactor(extension-compiler): drop type casts from tsconfig parsing Co-Authored-By: Claude Fable 5 --- packages/extension-compiler/src/conciv-src.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/extension-compiler/src/conciv-src.ts b/packages/extension-compiler/src/conciv-src.ts index 4516dad82..15801eb71 100644 --- a/packages/extension-compiler/src/conciv-src.ts +++ b/packages/extension-compiler/src/conciv-src.ts @@ -38,17 +38,16 @@ type RawTsconfig = { extends: unknown } +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null +} + function parseTsconfig(path: string): RawTsconfig | null { try { const parsed: unknown = JSON.parse(readFileSync(path, 'utf8')) - if (typeof parsed !== 'object' || parsed === null) return null - const record = parsed as Record - const rawCompilerOptions = record.compilerOptions - const compilerOptions = - typeof rawCompilerOptions === 'object' && rawCompilerOptions !== null - ? (rawCompilerOptions as Record) - : {} - return {jsx: compilerOptions.jsx, jsxImportSource: compilerOptions.jsxImportSource, extends: record.extends} + if (!isRecord(parsed)) return null + const compilerOptions = isRecord(parsed.compilerOptions) ? parsed.compilerOptions : {} + return {jsx: compilerOptions.jsx, jsxImportSource: compilerOptions.jsxImportSource, extends: parsed.extends} } catch { return null }