@stencil/react-output-target
Version:
React output target for @stencil/core components.
284 lines (280 loc) • 9.03 kB
JavaScript
import { Project as _, VariableDeclarationKind as R } from "ts-morph";
import N from "node:path";
const I = (o) => o.toLowerCase().split("-").map((a) => a.charAt(0).toUpperCase() + a.slice(1)).join(""), P = (o) => o.replace(/-([_a-z])/g, (a, r) => r.toUpperCase()), U = (o) => o.replace(/\/([a-z])/g, (a, r) => r.toUpperCase()), j = (o) => {
const a = U(o);
return P(`on-${a}`);
}, x = async ({
components: o,
project: a,
outDir: r
}) => {
const m = a || new _({ useInMemoryFileSystem: !0 }), h = `/* eslint-disable */
`, u = `/**
* 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.
*/
`, g = N.join(r || "", "components.ts"), l = m.createSourceFile(g, u + h, {
overwrite: !0
});
for (const T of o) {
const d = T.tagName, i = I(d), e = T.tagName;
l.addExportDeclaration({
moduleSpecifier: `./${e}.js`,
namedExports: [i]
});
}
return l.organizeImports(), l.formatText(), await l.save(), l;
}, O = ({
components: o,
stencilPackageName: a,
customElementsDir: r,
hydrateModule: m,
clientModule: h,
serializeShadowRoot: u
}) => {
const g = new _({ useInMemoryFileSystem: !0 }), l = m ? "" : `'use client';
`, T = `/**
* 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.
*/
`, d = `/* eslint-disable */
`, i = m ? [
"// @ts-ignore - ignore potential type issues as the project is importing itself",
`import * as clientComponents from '${h}';`,
"",
"import { createComponent, type SerializeShadowRootOptions, type HydrateModule, type ReactWebComponent, type DynamicFunction } from '@stencil/react-output-target/ssr';"
].join(`
`) : "import { createComponent } from '@stencil/react-output-target/runtime';", e = g.createSourceFile(
"component.ts",
`${l}${T}${d}
import React from 'react';
${i}
import type { EventName, StencilReactComponent } from '@stencil/react-output-target/runtime';
`
);
m && e.addVariableStatement({
isExported: !0,
declarationKind: R.Const,
declarations: [
{
name: "serializeShadowRoot",
type: "SerializeShadowRootOptions",
initializer: u ? JSON.stringify(u) : '{ default: "declarative-shadow-dom" }'
}
]
});
for (const s of o) {
const f = s.tagName, c = I(f), n = `${c}Element`, p = `${c}CustomEvent`;
e.addImportDeclaration({
moduleSpecifier: `${a}/${r}/${f}.js`,
namedImports: [
{
name: c,
alias: n
},
{
name: "defineCustomElement",
alias: `define${c}`
}
]
});
const y = (s.events || []).filter((t) => t.internal === !1), E = [];
for (const t of y)
if (Object.keys(t.complexType.references).length > 0) {
for (const F of Object.keys(t.complexType.references))
t.complexType.references[F].location === "global" || e.addImportDeclaration({
moduleSpecifier: a,
namedImports: [
{
name: F,
isTypeOnly: !0
}
]
});
e.addImportDeclaration({
moduleSpecifier: a,
namedImports: [
{
name: p,
isTypeOnly: !0
}
]
}), E.push({
originalName: t.name,
name: j(t.name),
type: `EventName<${p}<${t.complexType.original}>>`
});
} else
E.push({
originalName: t.name,
name: j(t.name),
type: `EventName<CustomEvent<${t.complexType.original}>>`
});
const C = `${c}Events`;
e.addTypeAlias({
isExported: !0,
name: C,
type: E.length > 0 ? `{ ${E.map((t) => `${t.name}: ${t.type}`).join(`,
`)} }` : "NonNullable<unknown>"
});
const S = `/*@__PURE__*/ createComponent<${n}, ${C}>({
tagName: '${f}',
elementClass: ${n},
// @ts-ignore - ignore potential React type mismatches between the Stencil Output Target and your project.
react: React,
events: {${E.map((t) => `${t.name}: '${t.originalName}'`).join(`,
`)}} as ${C},
defineCustomElement: define${c}
})`, b = `/*@__PURE__*/ createComponent<${n}, ${C}>({
tagName: '${f}',
properties: {${s.properties.filter((t) => !!t.attribute).map((t) => `${t.name}: '${t.attribute}'`).join(`,
`)}},
hydrateModule: import('${m}') as Promise<HydrateModule>,
clientModule: clientComponents.${c} as ReactWebComponent<${n}, ${C}>,
serializeShadowRoot,
})`;
e.addVariableStatement({
isExported: !0,
declarationKind: R.Const,
// React as never is a hack to by-pass a @types/react issue.
declarations: [
{
name: c,
type: `StencilReactComponent<${n}, ${C}>`,
initializer: m ? b : S
}
]
});
}
return e.organizeImports(), e.formatText(), e.getFullText();
}, D = async ({
stencilPackageName: o,
components: a,
outDir: r,
esModules: m,
customElementsDir: h,
excludeComponents: u,
project: g,
hydrateModule: l,
clientModule: T,
excludeServerSideRenderingFor: d,
serializeShadowRoot: i
}) => {
const e = [], s = a.filter((n) => !(n.internal === !0 || u != null && u.includes(n.tagName)));
if (s.length === 0)
return [];
const f = {};
function c(n, p = "components") {
const y = N.join(r, `${p}.ts`), E = O({
components: n,
stencilPackageName: o,
customElementsDir: h
});
if (f[y] = E, l) {
const C = N.join(r, `${p}.server.ts`), S = O({
components: n.filter(
(b) => !d || !d.includes(b.tagName)
),
stencilPackageName: o,
customElementsDir: h,
hydrateModule: l,
clientModule: T,
serializeShadowRoot: i
});
f[C] = S;
}
}
if (m) {
for (const p of s)
c([p], p.tagName);
const n = await x({ components: s, project: g, outDir: r });
e.push(n);
} else
c(s);
return await Promise.all(
Object.entries(f).map(async ([n, p]) => {
const y = g.createSourceFile(n, p, { overwrite: !0 });
await y.save(), e.push(y);
})
), e;
}, $ = "react-output-target", M = "dist/components", w = "dist-custom-elements", v = "dist-hydrate-script", q = ({
outDir: o,
esModules: a,
stencilPackageName: r,
excludeComponents: m,
customElementsDir: h,
hydrateModule: u,
clientModule: g,
excludeServerSideRenderingFor: l,
serializeShadowRoot: T
}) => {
let d = M;
return {
type: "custom",
name: $,
validate(i) {
if (h)
d = h;
else {
const e = (i.outputTargets || []).find(
(s) => s.type === w
);
if (e == null)
throw new Error(
`The '${$}' requires '${w}' output target. Add { type: '${w}' }, to the outputTargets config.`
);
if (e.dir !== void 0 && (d = e.dir), e.externalRuntime !== !1)
throw new Error(
`The '${$}' requires the '${w}' output target to have 'externalRuntime: false' set in its configuration.`
);
}
if (u) {
if ((i.outputTargets || []).find((s) => s.type === v) == null)
throw new Error(
`The '${$}' requires '${v}' output target when the 'hydrateModule' option is set. Add { type: '${v}' }, to the outputTargets config.`
);
if (g == null)
throw new Error(
`The '${$}' requires the 'clientModule' option when the 'hydrateModule' option is set. Please provide the clientModule manually to the ${$} output target.`
);
}
if (!o)
throw new Error("The 'outDir' option is required.");
if (r === void 0) {
if (i.sys && i.packageJsonFilePath) {
const { name: e } = JSON.parse(i.sys.readFileSync(i.packageJsonFilePath, "utf8"));
r = e;
}
if (!r)
throw new Error(
`Unable to find the package name in the package.json file: ${i.packageJsonFilePath}. Please provide the stencilPackageName manually to the ${$} output target.`
);
}
},
async generator(i, e, s) {
const f = s.createTimeSpan(`generate ${$} started`, !0), c = s.components, n = new _(), p = await D({
outDir: o,
components: c,
stencilPackageName: r,
customElementsDir: d,
excludeComponents: m,
esModules: a === !0,
project: n,
hydrateModule: u,
clientModule: g,
excludeServerSideRenderingFor: l,
serializeShadowRoot: T
});
await Promise.all(
p.map((y) => e.fs.writeFile(y.getFilePath(), y.getFullText()))
), f.finish(`generate ${$} finished`);
},
__internal_getCustomElementsDir() {
return d;
}
};
};
export {
q as reactOutputTarget
};
//# sourceMappingURL=index.js.map