@lmc-eu/spirit-analytics
Version:
Analytic tools for Spirit Design System
221 lines (211 loc) • 7.58 kB
JavaScript
import {
ROOT_PATH,
_dirname,
constants_exports,
errorMessage,
getOutputPath,
getVersions,
helpers_exports,
infoMessage,
react_scanner_config_default,
spiritAdoptionProcessor_default,
timestamp
} from "./chunk-JUL5L4SB.js";
// src/cli.ts
import sade from "sade";
import { fs as fs3, path as path3 } from "zx";
// src/scanner.ts
import { fs as fs2 } from "zx";
// src/runner.ts
import { path as path2 } from "zx";
// src/scanners/reactScanner.ts
import scanner from "react-scanner";
async function reactScanner(config) {
const output2 = await scanner.run({ ...config });
return output2;
}
// src/scanners/twigScanner.ts
import { fs, glob, path } from "zx";
function getComponentsFromDirectory(directoryPath) {
return fs.readdirSync(directoryPath).map((file) => `${file.charAt(0).toUpperCase()}${file.slice(1, -5)}`);
}
function getPathsFromYamlConfig(configFile) {
const twigXConfigLines = fs.readFileSync(configFile, "utf8").split("\n");
return twigXConfigLines.filter((line) => line.trim().startsWith("-")).map(
(line) => `${line.trim().substring(1).trim().replace(/"/g, "").replace(/^%kernel.\w+%/, ".")}/*.twig`
);
}
async function getLocalComponentsFromPaths(paths) {
return glob(paths, (error, files) => {
if (!error) {
return files.map(
(file) => path.basename(file).charAt(0).toUpperCase() + path.basename(file).slice(1, -5)
);
}
return [];
});
}
function determineModuleNameFromComponents(nodeName, localComponents, baseComponents) {
if (baseComponents.includes(nodeName)) {
return "@lmc-eu/spirit-web-twig";
}
const pascalCaseRegex = /^([A-Z][a-z0-9]+)+$/;
if (localComponents.includes(nodeName) || nodeName.match(pascalCaseRegex)) {
return "local_component";
}
return "html_element";
}
function searchFileForComponents(file, localComponents, baseComponents) {
const reStartTag = /<([a-zA-Z][a-zA-Z0-9]*)([^>]*)>/g;
const reAttr = /([\w-]+)="?([^"]*)"?/g;
const result = {};
const fileContent = fs.readFileSync(file, "utf-8");
let match = reStartTag.exec(fileContent);
while (match !== null) {
const [, nodeName, attrs] = match;
const nodeStartPos = match.index;
const numLineBreaks = fileContent.slice(0, nodeStartPos).match(/\n/g)?.length ?? 0;
const moduleName = determineModuleNameFromComponents(nodeName, localComponents, baseComponents);
const fullName = `${moduleName}:${nodeName}`;
const node = {
path: `${file}:${numLineBreaks + 1}`,
props: {}
};
attrs.replace(reAttr, (attrMatchString, name, value) => {
node.props[name] = value.replace(/\n\s+/g, "");
return "";
});
if (!result[fullName]) {
result[fullName] = [];
}
result[fullName].push(node);
match = reStartTag.exec(fileContent);
}
return result;
}
function searchDirectoryForComponents(dir, localComponents, baseComponents, exclude) {
let result = {};
if (!exclude.includes(path.basename(dir))) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
const fileStat = fs.lstatSync(filePath);
if (fileStat.isDirectory()) {
result = { ...result, ...searchDirectoryForComponents(filePath, localComponents, baseComponents, exclude) };
} else if (path.extname(filePath) === ".twig") {
result = { ...result, ...searchFileForComponents(filePath, localComponents, baseComponents) };
}
});
}
return result;
}
var output = (data, destination) => {
fs.mkdirSync(path.dirname(destination), { recursive: true });
fs.writeFileSync(destination, JSON.stringify(data, null, 2));
};
async function twigScanner(options) {
const spiritComponents = getComponentsFromDirectory(path.resolve(process.cwd(), options.coreComponentsPath || ""));
const twigXPaths = getPathsFromYamlConfig(path.resolve(process.cwd(), options.configFile || ""));
const localComponents = await getLocalComponentsFromPaths(twigXPaths);
const result = searchDirectoryForComponents(
path.resolve(process.cwd(), options.rootPath || ""),
localComponents,
spiritComponents,
options.exclude || []
);
output(result, path.resolve(process.cwd(), options.outputFile || ""));
return result;
}
// src/runner.ts
var getTrackedData = async ({
config,
source,
type
}) => {
const crawlFrom = path2.resolve(source) || path2.resolve(_dirname, ROOT_PATH);
const spiritVersion = await getVersions(crawlFrom);
let reactOutput = {};
let twigOutput = {};
if (type === "react" || type === null) {
reactOutput = await reactScanner({ ...config.react, crawlFrom });
}
if (type === "twig" || type === null) {
twigOutput = await twigScanner({ ...config.twig, crawlFrom });
}
return {
spiritVersion,
trackedData: {
react: reactOutput,
twig: twigOutput
}
};
};
var runner = (config, source, type) => getTrackedData({ config, source, type });
// src/scanner.ts
var getRunnerCall = async ({ outputPath, config, source, type }) => {
const result = await runner(config, source, type);
if (outputPath) {
fs2.writeFile(getOutputPath(outputPath, timestamp()), JSON.stringify(result, null, 2), "utf8").then(() => {
infoMessage(`Successfully created ${timestamp()}.json file in the ${outputPath}`);
});
} else {
}
};
async function scanner2({ source, outputPath, config, type }) {
try {
await getRunnerCall({ outputPath, config, source, type });
} catch (err) {
errorMessage(`
${err}`);
}
}
var scanner_default = scanner2;
// src/cli.ts
var packageJson = fs3.readJsonSync(path3.resolve(_dirname, "./package.json"));
async function cli(args) {
sade("analytics", true).version(packageJson.version).describe(packageJson.description).option("-s, --source", "Source to scan from").example("-s assets").option("-o, --output", "Output path for parsed files").example("-o path/to/folder").option("-c --config", "Path to scanner config").example("-c path/to/scanner.config.js").option("-t --type", "Type of scanner").example("-t react").action(async ({ output: output2, config, source, type }) => {
let selectedConfig;
if (config && !fs3.existsSync(config)) {
errorMessage("Could not find config file");
process.exit(1);
} else if (config && fs3.existsSync(config)) {
infoMessage(`Using provided config file: ${config}`);
selectedConfig = path3.resolve(process.cwd(), config);
} else {
infoMessage("Using default config file");
selectedConfig = path3.resolve(_dirname, "./spirit-analytics.config.js");
}
if (output2 && !fs3.existsSync(output2)) {
errorMessage("Path does not exists");
process.exit(1);
}
const { default: loadedConfig } = await import(selectedConfig);
let selectedType = null;
if (type) {
selectedType = type;
}
if (source) {
scanner_default({ source, outputPath: output2, config: loadedConfig, type: selectedType });
infoMessage(`Start scanning: ${source}`);
} else {
scanner_default({
source: path3.resolve(process.cwd(), ROOT_PATH),
outputPath: output2,
config: loadedConfig,
type: selectedType
});
infoMessage("Start scanning from default scope");
}
}).parse(args);
}
// src/types.ts
var types_exports = {};
export {
cli,
constants_exports as constants,
helpers_exports as helpers,
react_scanner_config_default as reactScannerConfig,
scanner_default as scanner,
spiritAdoptionProcessor_default as spiritAdoptionProcessor,
types_exports as types
};