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