UNPKG

@stencil/react-output-target

Version:

React output target for @stencil/core components.

401 lines (392 loc) 13.9 kB
import N from "node:path"; import { Project as P, VariableDeclarationKind as M } from "ts-morph"; const _ = (o) => o.toLowerCase().split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(""), z = (o) => o.replace(/-([_a-z])/g, (s, u) => u.toUpperCase()), H = (o) => o.replace(/\/([a-z])/g, (s, u) => u.toUpperCase()), J = (o) => { const s = H(o); return z(`on-${s}`); }, O = (o) => o.replace(/\/\/.*$/gm, "").replace(/\n/g, " ").replace(/\s{2,}/g, " ").trim(), K = async ({ components: o, project: s, outDir: u }) => { const i = s || new P({ useInMemoryFileSystem: !0 }), n = `/* eslint-disable */ `, $ = `/** * This file was automatically generated by the Stencil React Output Target. * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. */ `, f = N.join(u || "", "components.ts"), d = i.createSourceFile(f, $ + n, { overwrite: !0 }); for (const y of o) { const b = y.tagName, v = _(b), T = y.tagName; d.addExportDeclaration({ moduleSpecifier: `./${T}.js`, namedExports: [v] }); } return d.organizeImports(), d.formatText(), await d.save(), d; }, A = ({ components: o, stencilPackageName: s, customElementsDir: u, hydrateModule: i, clientModule: n, serializeShadowRoot: $, transformTag: f }) => { const d = new P({ useInMemoryFileSystem: !0 }), y = i ? "" : `'use client'; `, b = `/** * This file was automatically generated by the Stencil React Output Target. * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. */ `, v = `/* eslint-disable */ `, T = f ? `import { getTagTransformer } from './tag-transformer.js'; ` : "", l = i ? [ "// @ts-ignore - ignore potential type issues as the project is importing itself", `import * as clientComponents from '${n}';`, T, "import { createComponent, type SerializeShadowRootOptions, type HydrateModule, type ReactWebComponent, type DynamicFunction } from '@stencil/react-output-target/ssr';" ].filter(Boolean).join(` `) : "import { createComponent } from '@stencil/react-output-target/runtime';", c = f ? `import { transformTag } from './tag-transformer.js'; ` : "", e = d.createSourceFile( "component.ts", `${y}${b}${v} import React from 'react'; ${l} import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime'; ${c} ` ); i && e.addVariableStatement({ isExported: !0, declarationKind: M.Const, declarations: [ { name: "serializeShadowRoot", type: "SerializeShadowRootOptions", initializer: $ ? JSON.stringify($) : '{ default: "declarative-shadow-dom" }' } ] }); for (const h of o) { const a = h.tagName, r = _(a), t = `${r}Element`, g = `${r}CustomEvent`; e.addImportDeclaration({ moduleSpecifier: `${s}/${u}/${a}.js`, namedImports: [ { name: r, alias: t }, { name: "defineCustomElement", alias: `define${r}` } ] }); const E = (h.events || []).filter((m) => m.internal === !1), S = [], p = /* @__PURE__ */ new Set(); let j = !1; for (const m of E) { if (Object.keys(m.complexType.references).length > 0) for (const F of Object.keys(m.complexType.references)) !(m.complexType.references[F].location === "global") && !p.has(F) && (p.add(F), e.addImportDeclaration({ moduleSpecifier: s, namedImports: [ { name: F, isTypeOnly: !0 } ] })); j || (j = !0, e.addImportDeclaration({ moduleSpecifier: s, namedImports: [ { name: g, isTypeOnly: !0 } ] })), S.push({ originalName: m.name, name: J(m.name), type: `EventName<${g}<${O(m.complexType.original)}>>` }); } const w = `${r}Events`; e.addTypeAlias({ isExported: !0, name: w, type: S.length > 0 ? `{ ${S.map((m) => `${m.name}: ${m.type}`).join(`, `)} }` : "NonNullable<unknown>" }); const R = f ? `, transformTag` : "", L = `/*@__PURE__*/ createComponent<${t}, ${w}>({ tagName: '${a}', elementClass: ${t}, // @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project. react: React, events: {${S.map((m) => `${m.name}: '${m.originalName}'`).join(`, `)}} as ${w}, defineCustomElement: define${r}${R} })`, D = f ? `, getTagTransformer` : "", U = `/*@__PURE__*/ createComponent<${t}, ${w}>({ tagName: '${a}', properties: {${h.properties.filter((m) => !!m.attribute).map((m) => `${m.name}: '${m.attribute}'`).join(`, `)}}, hydrateModule: import('${i}') as Promise<HydrateModule>, clientModule: clientComponents.${r} as ReactWebComponent<${t}, ${w}>, serializeShadowRoot${D} })`; e.addVariableStatement({ isExported: !0, declarationKind: M.Const, // React as never is a hack to by-pass a @types/react issue. declarations: [ { name: r, type: `StencilReactComponent<${t}, ${w}>`, initializer: i ? U : L } ] }); } return e.organizeImports(), e.formatText(), e.getFullText(); }, V = ({ stencilPackageName: o, customElementsDir: s }) => `/* eslint-disable */ /* tslint:disable */ import { setTagTransformer as clientSetTagTransformer } from '${o}/${s}/index.js'; let tagTransformer: ((tagName: string) => string) | undefined; export const setTagTransformer = (transformer: (tagName: string) => string) => { clientSetTagTransformer(transformer); tagTransformer = transformer; }; export const transformTag = (tag: string): string => { return tagTransformer ? tagTransformer(tag) : tag; }; export const getTagTransformer = () => tagTransformer; `, q = async ({ stencilPackageName: o, components: s, outDir: u, esModules: i, customElementsDir: n, excludeComponents: $, project: f, hydrateModule: d, clientModule: y, excludeServerSideRenderingFor: b, serializeShadowRoot: v, transformTag: T }) => { const l = [], c = s.filter((a) => !(a.internal === !0 || $ != null && $.includes(a.tagName))); if (c.length === 0) return []; const e = {}; function h(a, r = "components") { const t = N.join(u, `${r}.ts`), g = A({ components: a, stencilPackageName: o, customElementsDir: n, transformTag: T }); if (e[t] = g, T) { const E = N.join(u, "tag-transformer.ts"); e[E] = V({ stencilPackageName: o, customElementsDir: n }); } if (d) { const E = N.join(u, `${r}.server.ts`), S = A({ components: a.filter( (p) => !b || !b.includes(p.tagName) ), stencilPackageName: o, customElementsDir: n, hydrateModule: d, clientModule: y, serializeShadowRoot: v, transformTag: T }); e[E] = S; } } if (i) { for (const r of c) h([r], r.tagName); const a = await K({ components: c, project: f, outDir: u }); l.push(a); } else h(c); return await Promise.all( Object.entries(e).map(async ([a, r]) => { const t = f.createSourceFile(a, r, { overwrite: !0 }); await t.save(), l.push(t); }) ), l; }, G = (o) => `on${o.toLowerCase()}`, W = ({ components: o, stencilPackageName: s, excludeComponents: u }) => { var y, b, v, T, l, c; const i = o.filter((e) => !(e.internal === !0 || u != null && u.includes(e.tagName))); if (i.length === 0) return ""; const n = []; n.push(`/** * This file was automatically generated by the Stencil React Output Target. * Changes to this file may cause incorrect behavior and will be lost if the code is regenerated. * * This file provides TypeScript type definitions for using Stencil web components * as native custom elements in React 19+. * * Usage: * Import this file in your React application to get type support for custom elements: * \`\`\`tsx * import '${s}/react-native-types'; * \`\`\` */ /* eslint-disable */ /* tslint:disable */ `), n.push("// @ts-ignore - React types may not be available in all build contexts"), n.push("import 'react';"), n.push("// @ts-ignore - React types may not be available in all build contexts"), n.push("import type { DetailedHTMLProps, HTMLAttributes } from 'react';"); const $ = /* @__PURE__ */ new Set(), f = /* @__PURE__ */ new Set(); for (const e of i) { const h = _(e.tagName), a = (e.events || []).filter((t) => !t.internal); a.length > 0 && $.add(`${h}CustomEvent`); for (const t of a) if ((y = t.complexType) != null && y.references) for (const [g, E] of Object.entries(t.complexType.references)) E.location !== "global" && f.add(g); const r = (e.properties || []).filter((t) => !t.internal); for (const t of r) if ((b = t.complexType) != null && b.references) for (const [g, E] of Object.entries(t.complexType.references)) E.location !== "global" && f.add(g); } const d = /* @__PURE__ */ new Set([...$, ...f]); d.size > 0 && n.push(`import type { ${Array.from(d).sort().join(", ")} } from '${s}';`), n.push(""); for (const e of i) { const h = e.tagName, a = _(h), r = `${a}NativeProps`, t = `${a}CustomEvent`, g = [], E = (e.properties || []).filter((p) => !p.internal); for (const p of E) { const j = ((v = p.complexType) == null ? void 0 : v.original) || "any", w = (T = p.docs) != null && T.text ? ` /** ${p.docs.text.trim()} */ ` : "", R = p.name; g.push(`${w} '${R}'?: ${O(j)};`); } const S = (e.events || []).filter((p) => !p.internal); for (const p of S) { const j = O(((l = p.complexType) == null ? void 0 : l.original) || "void"), w = (c = p.docs) != null && c.text ? ` /** Event: ${p.name} - ${p.docs.text.trim()} */ ` : ` /** Event: ${p.name} */ `, R = G(p.name); g.push(`${w} '${R}'?: (event: ${t}<${j}>) => void;`); } g.length > 0 ? (n.push(`interface ${r} {`), n.push(g.join(` `)), n.push("}")) : n.push(`interface ${r} {}`), n.push(""); } n.push("declare module 'react/jsx-runtime' {"), n.push(" namespace JSX {"), n.push(" interface IntrinsicElements {"); for (const e of i) { const h = e.tagName, a = _(h), r = `${a}NativeProps`, t = `HTML${a}Element`; n.push( ` '${h}': DetailedHTMLProps<HTMLAttributes<${t}> & ${r}, ${t}>;` ); } return n.push(" }"), n.push(" }"), n.push("}"), n.push(""), n.join(` `); }, k = "react-native-types.d.ts", C = "react-output-target", B = "dist/components", I = "dist-custom-elements", x = "dist-hydrate-script", ee = ({ outDir: o, nativeTypesPath: s, esModules: u, stencilPackageName: i, excludeComponents: n, customElementsDir: $, hydrateModule: f, clientModule: d, excludeServerSideRenderingFor: y, serializeShadowRoot: b, transformTag: v }) => { let T = B; return { type: "custom", name: C, validate(l) { if (!o && !s) throw new Error(`The '${C}' requires either 'outDir' or 'nativeTypesPath' to be specified.`); if (o) { if ($) T = $; else { const c = (l.outputTargets || []).find( (e) => e.type === I ); if (c == null) throw new Error( `The '${C}' requires '${I}' output target when 'outDir' is specified. Add { type: '${I}' }, to the outputTargets config.` ); if (c.dir !== void 0 && (T = c.dir), c.externalRuntime !== !1) throw new Error( `The '${C}' requires the '${I}' output target to have 'externalRuntime: false' set in its configuration.` ); } if (f) { if ((l.outputTargets || []).find((e) => e.type === x) == null) throw new Error( `The '${C}' requires '${x}' output target when the 'hydrateModule' option is set. Add { type: '${x}' }, to the outputTargets config.` ); if (d == null) throw new Error( `The '${C}' requires the 'clientModule' option when the 'hydrateModule' option is set. Please provide the clientModule manually to the ${C} output target.` ); } } if (i === void 0) { if (l.sys && l.packageJsonFilePath) { const { name: c } = JSON.parse(l.sys.readFileSync(l.packageJsonFilePath, "utf8")); i = c; } if (!i) throw new Error( `Unable to find the package name in the package.json file: ${l.packageJsonFilePath}. Please provide the stencilPackageName manually to the ${C} output target.` ); } }, async generator(l, c, e) { const h = e.createTimeSpan(`generate ${C} started`, !0), a = e.components; if (o) { const r = new P(), t = await q({ outDir: o, components: a, stencilPackageName: i, customElementsDir: T, excludeComponents: n, esModules: u === !0, project: r, hydrateModule: f, clientModule: d, excludeServerSideRenderingFor: y, serializeShadowRoot: b, transformTag: v }); await Promise.all( t.map((g) => c.fs.writeFile(g.getFilePath(), g.getFullText())) ); } if (s) { const r = W({ components: a, stencilPackageName: i, excludeComponents: n }); if (r) { let t = s.endsWith(".d.ts") ? s : N.join(s, k); !N.isAbsolute(t) && l.rootDir && (t = N.join(l.rootDir, t)), await c.fs.writeFile(t, r); } } h.finish(`generate ${C} finished`); }, __internal_getCustomElementsDir() { return T; } }; }; export { ee as reactOutputTarget }; //# sourceMappingURL=index.js.map