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