161 lines
3.8 KiB
JavaScript
161 lines
3.8 KiB
JavaScript
import path from "node:path";
|
|
import { SOURCE_DIR } from "../../../utils/index.js";
|
|
import getPublicDocFunctionality from "./get-public-doc-functionality.js";
|
|
import {
|
|
createIdentifier,
|
|
createMemberExpression,
|
|
createStringLiteral,
|
|
} from "./utilities.js";
|
|
|
|
const DOC_MODULE_DIRECTORY = path.join(SOURCE_DIR, "document/");
|
|
const PUBLIC_DOC_MODULE_PATH = path.join(SOURCE_DIR, "document/public.js");
|
|
|
|
/**
|
|
* @param {import("@babel/types").Node} node
|
|
* @returns {boolean}
|
|
*/
|
|
function getImportDeclarationReplacement(node, file) {
|
|
if (node.type !== "ImportDeclaration") {
|
|
return;
|
|
}
|
|
|
|
const source = node.source.value;
|
|
|
|
if (!source.startsWith(".")) {
|
|
return;
|
|
}
|
|
|
|
const resolved = path.join(file, `../${source}`);
|
|
|
|
if (
|
|
!resolved.startsWith(DOC_MODULE_DIRECTORY) ||
|
|
resolved === PUBLIC_DOC_MODULE_PATH
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const removed = [];
|
|
const specifiers = node.specifiers
|
|
.map((specifier) => {
|
|
const { imported, local } = specifier;
|
|
if (imported.type !== "Identifier" || local.type !== "Identifier") {
|
|
return specifier;
|
|
}
|
|
|
|
const { name } = imported;
|
|
|
|
const replacement = getPublicDocFunctionality(name, resolved);
|
|
|
|
if (!replacement) {
|
|
return specifier;
|
|
}
|
|
|
|
removed.push({ variable: local.name, ...replacement });
|
|
})
|
|
.filter(Boolean);
|
|
|
|
if (removed.length === 0) {
|
|
return;
|
|
}
|
|
|
|
return {
|
|
node:
|
|
removed.length === node.specifiers.length
|
|
? undefined
|
|
: { ...node, specifiers },
|
|
removed,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {import("@babel/types").Program} node
|
|
* @returns {import("@babel/types").Program}
|
|
*/
|
|
function transformProgramWithoutCache(program, file) {
|
|
const replacements = [];
|
|
const body = program.body
|
|
.map((node) => {
|
|
const replacement = getImportDeclarationReplacement(node, file);
|
|
|
|
if (!replacement) {
|
|
return node;
|
|
}
|
|
|
|
replacements.push(...replacement.removed);
|
|
|
|
return replacement.node;
|
|
})
|
|
.filter(Boolean);
|
|
|
|
if (replacements.length === 0) {
|
|
return;
|
|
}
|
|
|
|
const identityPrefix = "__doc_";
|
|
|
|
const grouped = [];
|
|
for (const replacement of replacements) {
|
|
const group = grouped.find(
|
|
(searching) => searching.namespace === replacement.namespace,
|
|
);
|
|
if (!group) {
|
|
grouped.push({
|
|
namespace: replacement.namespace,
|
|
replacements: [replacement],
|
|
});
|
|
} else {
|
|
group.replacements.push(replacement);
|
|
}
|
|
}
|
|
|
|
body.unshift(
|
|
{
|
|
type: "ImportDeclaration",
|
|
source: createStringLiteral(PUBLIC_DOC_MODULE_PATH),
|
|
specifiers: grouped.map(({ namespace }) => ({
|
|
type: "ImportSpecifier",
|
|
imported: createIdentifier(namespace),
|
|
local: createIdentifier(`${identityPrefix}${namespace}`),
|
|
})),
|
|
},
|
|
{
|
|
type: "VariableDeclaration",
|
|
kind: "const",
|
|
declarations: grouped.map(({ namespace, replacements }) => ({
|
|
type: "VariableDeclarator",
|
|
id: {
|
|
type: "ObjectPattern",
|
|
properties: replacements.map(({ variable, name }) => ({
|
|
type: "ObjectProperty",
|
|
key: createIdentifier(name),
|
|
value: createIdentifier(variable),
|
|
shorthand: name === variable,
|
|
})),
|
|
},
|
|
init: createMemberExpression(`${identityPrefix}${namespace}`),
|
|
})),
|
|
},
|
|
);
|
|
|
|
return { ...program, body };
|
|
}
|
|
|
|
const cache = new WeakMap();
|
|
function transformProgram(program, file) {
|
|
if (program.type !== "Program") {
|
|
return program;
|
|
}
|
|
if (!cache.has(program)) {
|
|
cache.set(program, transformProgramWithoutCache(program, file) ?? program);
|
|
}
|
|
|
|
return cache.get(program);
|
|
}
|
|
|
|
export default {
|
|
shouldSkip: (text, file, buildOptions) =>
|
|
!buildOptions.reuseDocModule || file.startsWith(DOC_MODULE_DIRECTORY),
|
|
test: (program, file) => program !== transformProgram(program, file),
|
|
transform: transformProgram,
|
|
};
|