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