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