Migration datamodels !
This commit is contained in:
207
node_modules/less/scripts/coverage-lines.js
generated
vendored
Normal file
207
node_modules/less/scripts/coverage-lines.js
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Generates a line-by-line coverage report showing uncovered lines
|
||||
* Reads from LCOV format and displays in terminal
|
||||
* Also outputs JSON file with uncovered lines for programmatic access
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const lcovPath = path.join(__dirname, '..', 'coverage', 'lcov.info');
|
||||
const jsonOutputPath = path.join(__dirname, '..', 'coverage', 'uncovered-lines.json');
|
||||
|
||||
if (!fs.existsSync(lcovPath)) {
|
||||
console.error('LCOV coverage file not found. Run pnpm test:coverage first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const lcovContent = fs.readFileSync(lcovPath, 'utf8');
|
||||
|
||||
// Parse LCOV format
|
||||
const files = [];
|
||||
let currentFile = null;
|
||||
|
||||
const lines = lcovContent.split('\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i];
|
||||
|
||||
// SF: source file
|
||||
if (line.startsWith('SF:')) {
|
||||
if (currentFile) {
|
||||
files.push(currentFile);
|
||||
}
|
||||
const filePath = line.substring(3);
|
||||
// Only include src/ files (not less-browser) and bin/
|
||||
// Exclude abstract base classes (they're meant to be overridden)
|
||||
const normalized = filePath.replace(/\\/g, '/');
|
||||
const abstractClasses = ['abstract-file-manager', 'abstract-plugin-loader'];
|
||||
const isAbstract = abstractClasses.some(abstract => normalized.includes(abstract));
|
||||
|
||||
if (!isAbstract &&
|
||||
((normalized.includes('src/less/') && !normalized.includes('src/less-browser/')) ||
|
||||
normalized.includes('src/less-node/') ||
|
||||
normalized.includes('bin/'))) {
|
||||
// Extract relative path - match src/less/... or src/less-node/... or bin/...
|
||||
// Path format: src/less/tree/debug-info.js or src/less-node/file-manager.js
|
||||
// Match from src/ or bin/ to end of path
|
||||
const match = normalized.match(/(src\/[^/]+\/.+|bin\/.+)$/);
|
||||
const relativePath = match ? match[1] : (normalized.includes('/src/') || normalized.includes('/bin/') ? normalized.split('/').slice(-3).join('/') : path.basename(filePath));
|
||||
currentFile = {
|
||||
path: relativePath,
|
||||
fullPath: filePath,
|
||||
uncoveredLines: [],
|
||||
uncoveredLineCode: {}, // line number -> source code
|
||||
totalLines: 0,
|
||||
coveredLines: 0
|
||||
};
|
||||
} else {
|
||||
currentFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
// DA: line data (line number, execution count)
|
||||
if (currentFile && line.startsWith('DA:')) {
|
||||
const match = line.match(/^DA:(\d+),(\d+)$/);
|
||||
if (match) {
|
||||
const lineNum = parseInt(match[1], 10);
|
||||
const count = parseInt(match[2], 10);
|
||||
currentFile.totalLines++;
|
||||
if (count > 0) {
|
||||
currentFile.coveredLines++;
|
||||
} else {
|
||||
currentFile.uncoveredLines.push(lineNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentFile) {
|
||||
files.push(currentFile);
|
||||
}
|
||||
|
||||
// Read source code for uncovered lines
|
||||
files.forEach(file => {
|
||||
if (file.uncoveredLines.length > 0 && fs.existsSync(file.fullPath)) {
|
||||
try {
|
||||
const sourceCode = fs.readFileSync(file.fullPath, 'utf8');
|
||||
const sourceLines = sourceCode.split('\n');
|
||||
file.uncoveredLines.forEach(lineNum => {
|
||||
// LCOV uses 1-based line numbers
|
||||
if (lineNum > 0 && lineNum <= sourceLines.length) {
|
||||
file.uncoveredLineCode[lineNum] = sourceLines[lineNum - 1].trim();
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
// If we can't read the source (e.g., it's in lib/ but we want src/), that's ok
|
||||
// We'll just skip the source code
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Filter to only files with uncovered lines and sort by coverage
|
||||
const filesWithGaps = files
|
||||
.filter(f => f.uncoveredLines.length > 0)
|
||||
.sort((a, b) => {
|
||||
const aPct = a.totalLines > 0 ? a.coveredLines / a.totalLines : 1;
|
||||
const bPct = b.totalLines > 0 ? b.coveredLines / b.totalLines : 1;
|
||||
return aPct - bPct;
|
||||
});
|
||||
|
||||
if (filesWithGaps.length === 0) {
|
||||
if (files.length === 0) {
|
||||
console.log('\n⚠️ No source files found in coverage data. This may indicate an issue with the coverage report.\n');
|
||||
} else {
|
||||
console.log('\n✅ All analyzed files have 100% line coverage!\n');
|
||||
console.log(`(Analyzed ${files.length} files from src/less/, src/less-node/, and bin/)\n`);
|
||||
}
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(100));
|
||||
console.log('Uncovered Lines Report');
|
||||
console.log('='.repeat(100) + '\n');
|
||||
|
||||
filesWithGaps.forEach(file => {
|
||||
const coveragePct = file.totalLines > 0
|
||||
? ((file.coveredLines / file.totalLines) * 100).toFixed(1)
|
||||
: '0.0';
|
||||
|
||||
console.log(`\n${file.path} (${coveragePct}% coverage)`);
|
||||
console.log('-'.repeat(100));
|
||||
|
||||
// Group consecutive lines into ranges
|
||||
const ranges = [];
|
||||
let start = file.uncoveredLines[0];
|
||||
let end = file.uncoveredLines[0];
|
||||
|
||||
for (let i = 1; i < file.uncoveredLines.length; i++) {
|
||||
if (file.uncoveredLines[i] === end + 1) {
|
||||
end = file.uncoveredLines[i];
|
||||
} else {
|
||||
ranges.push(start === end ? `${start}` : `${start}..${end}`);
|
||||
start = file.uncoveredLines[i];
|
||||
end = file.uncoveredLines[i];
|
||||
}
|
||||
}
|
||||
ranges.push(start === end ? `${start}` : `${start}..${end}`);
|
||||
|
||||
// Display ranges (max 5 per line for readability)
|
||||
const linesPerRow = 5;
|
||||
for (let i = 0; i < ranges.length; i += linesPerRow) {
|
||||
const row = ranges.slice(i, i + linesPerRow);
|
||||
console.log(` Lines: ${row.join(', ')}`);
|
||||
}
|
||||
|
||||
console.log(` Total uncovered: ${file.uncoveredLines.length} of ${file.totalLines} lines`);
|
||||
});
|
||||
|
||||
console.log('\n' + '='.repeat(100) + '\n');
|
||||
|
||||
// Write JSON output for programmatic access
|
||||
const jsonOutput = {
|
||||
generated: new Date().toISOString(),
|
||||
files: filesWithGaps.map(file => ({
|
||||
path: file.path,
|
||||
fullPath: file.fullPath,
|
||||
sourcePath: (() => {
|
||||
// Try to map lib/ path to src/ path
|
||||
const normalized = file.fullPath.replace(/\\/g, '/');
|
||||
if (normalized.includes('/lib/')) {
|
||||
return normalized.replace('/lib/', '/src/').replace(/\.js$/, '.ts');
|
||||
}
|
||||
return file.fullPath;
|
||||
})(),
|
||||
coveragePercent: file.totalLines > 0
|
||||
? parseFloat(((file.coveredLines / file.totalLines) * 100).toFixed(1))
|
||||
: 0,
|
||||
totalLines: file.totalLines,
|
||||
coveredLines: file.coveredLines,
|
||||
uncoveredLines: file.uncoveredLines,
|
||||
uncoveredLineCode: file.uncoveredLineCode || {},
|
||||
uncoveredRanges: (() => {
|
||||
const ranges = [];
|
||||
if (file.uncoveredLines.length === 0) return ranges;
|
||||
|
||||
let start = file.uncoveredLines[0];
|
||||
let end = file.uncoveredLines[0];
|
||||
|
||||
for (let i = 1; i < file.uncoveredLines.length; i++) {
|
||||
if (file.uncoveredLines[i] === end + 1) {
|
||||
end = file.uncoveredLines[i];
|
||||
} else {
|
||||
ranges.push({ start, end });
|
||||
start = file.uncoveredLines[i];
|
||||
end = file.uncoveredLines[i];
|
||||
}
|
||||
}
|
||||
ranges.push({ start, end });
|
||||
return ranges;
|
||||
})()
|
||||
}))
|
||||
};
|
||||
|
||||
fs.writeFileSync(jsonOutputPath, JSON.stringify(jsonOutput, null, 2), 'utf8');
|
||||
console.log('\n📄 Uncovered lines data written to: coverage/uncovered-lines.json\n');
|
||||
|
||||
158
node_modules/less/scripts/coverage-report.js
generated
vendored
Normal file
158
node_modules/less/scripts/coverage-report.js
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Generates a per-file coverage report table for src/ directories
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const coverageSummaryPath = path.join(__dirname, '..', 'coverage', 'coverage-summary.json');
|
||||
|
||||
if (!fs.existsSync(coverageSummaryPath)) {
|
||||
console.error('Coverage summary not found. Run pnpm test:coverage first.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const coverage = JSON.parse(fs.readFileSync(coverageSummaryPath, 'utf8'));
|
||||
|
||||
// Filter to only src/ files (less, less-node) and bin/ files
|
||||
// Note: src/less-browser/ is excluded because browser tests aren't included in coverage
|
||||
// Abstract base classes are excluded as they're meant to be overridden by implementations
|
||||
const abstractClasses = [
|
||||
'abstract-file-manager',
|
||||
'abstract-plugin-loader'
|
||||
];
|
||||
|
||||
const srcFiles = Object.entries(coverage)
|
||||
.filter(([filePath]) => {
|
||||
const normalized = filePath.replace(/\\/g, '/');
|
||||
// Exclude abstract classes
|
||||
if (abstractClasses.some(abstract => normalized.includes(abstract))) {
|
||||
return false;
|
||||
}
|
||||
return (normalized.includes('/src/less/') && !normalized.includes('/src/less-browser/')) ||
|
||||
normalized.includes('/src/less-node/') ||
|
||||
normalized.includes('/bin/');
|
||||
})
|
||||
.map(([filePath, data]) => {
|
||||
// Extract relative path from absolute path
|
||||
const normalized = filePath.replace(/\\/g, '/');
|
||||
// Match src/ paths or bin/ paths
|
||||
const match = normalized.match(/((?:src\/[^/]+\/[^/]+\/|bin\/).+)$/);
|
||||
const relativePath = match ? match[1] : path.basename(filePath);
|
||||
|
||||
return {
|
||||
path: relativePath,
|
||||
statements: data.statements,
|
||||
branches: data.branches,
|
||||
functions: data.functions,
|
||||
lines: data.lines
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
// Sort by directory first, then by coverage percentage
|
||||
const pathCompare = a.path.localeCompare(b.path);
|
||||
if (pathCompare !== 0) return pathCompare;
|
||||
return a.statements.pct - b.statements.pct;
|
||||
});
|
||||
|
||||
if (srcFiles.length === 0) {
|
||||
console.log('No src/ files found in coverage report.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Group by directory
|
||||
const grouped = {
|
||||
'src/less/': [],
|
||||
'src/less-node/': [],
|
||||
'bin/': []
|
||||
};
|
||||
|
||||
srcFiles.forEach(file => {
|
||||
if (file.path.startsWith('src/less/')) {
|
||||
grouped['src/less/'].push(file);
|
||||
} else if (file.path.startsWith('src/less-node/')) {
|
||||
grouped['src/less-node/'].push(file);
|
||||
} else if (file.path.startsWith('bin/')) {
|
||||
grouped['bin/'].push(file);
|
||||
}
|
||||
});
|
||||
|
||||
// Print table
|
||||
console.log('\n' + '='.repeat(100));
|
||||
console.log('Per-File Coverage Report (src/less/, src/less-node/, and bin/)');
|
||||
console.log('='.repeat(100));
|
||||
console.log('For line-by-line coverage details, open coverage/index.html in your browser.');
|
||||
console.log('='.repeat(100) + '\n');
|
||||
|
||||
Object.entries(grouped).forEach(([dir, files]) => {
|
||||
if (files.length === 0) return;
|
||||
|
||||
console.log(`\n${dir.toUpperCase()}`);
|
||||
console.log('-'.repeat(100));
|
||||
console.log(
|
||||
'File'.padEnd(50) +
|
||||
'Statements'.padStart(12) +
|
||||
'Branches'.padStart(12) +
|
||||
'Functions'.padStart(12) +
|
||||
'Lines'.padStart(12)
|
||||
);
|
||||
console.log('-'.repeat(100));
|
||||
|
||||
files.forEach(file => {
|
||||
const filename = file.path.replace(dir, '');
|
||||
const truncated = filename.length > 48 ? '...' + filename.slice(-45) : filename;
|
||||
|
||||
console.log(
|
||||
truncated.padEnd(50) +
|
||||
`${file.statements.pct.toFixed(1)}%`.padStart(12) +
|
||||
`${file.branches.pct.toFixed(1)}%`.padStart(12) +
|
||||
`${file.functions.pct.toFixed(1)}%`.padStart(12) +
|
||||
`${file.lines.pct.toFixed(1)}%`.padStart(12)
|
||||
);
|
||||
});
|
||||
|
||||
// Summary for this directory
|
||||
const totals = files.reduce((acc, file) => {
|
||||
acc.statements.total += file.statements.total;
|
||||
acc.statements.covered += file.statements.covered;
|
||||
acc.branches.total += file.branches.total;
|
||||
acc.branches.covered += file.branches.covered;
|
||||
acc.functions.total += file.functions.total;
|
||||
acc.functions.covered += file.functions.covered;
|
||||
acc.lines.total += file.lines.total;
|
||||
acc.lines.covered += file.lines.covered;
|
||||
return acc;
|
||||
}, {
|
||||
statements: { total: 0, covered: 0 },
|
||||
branches: { total: 0, covered: 0 },
|
||||
functions: { total: 0, covered: 0 },
|
||||
lines: { total: 0, covered: 0 }
|
||||
});
|
||||
|
||||
const stmtPct = totals.statements.total > 0
|
||||
? (totals.statements.covered / totals.statements.total * 100).toFixed(1)
|
||||
: '0.0';
|
||||
const branchPct = totals.branches.total > 0
|
||||
? (totals.branches.covered / totals.branches.total * 100).toFixed(1)
|
||||
: '0.0';
|
||||
const funcPct = totals.functions.total > 0
|
||||
? (totals.functions.covered / totals.functions.total * 100).toFixed(1)
|
||||
: '0.0';
|
||||
const linePct = totals.lines.total > 0
|
||||
? (totals.lines.covered / totals.lines.total * 100).toFixed(1)
|
||||
: '0.0';
|
||||
|
||||
console.log('-'.repeat(100));
|
||||
console.log(
|
||||
'TOTAL'.padEnd(50) +
|
||||
`${stmtPct}%`.padStart(12) +
|
||||
`${branchPct}%`.padStart(12) +
|
||||
`${funcPct}%`.padStart(12) +
|
||||
`${linePct}%`.padStart(12)
|
||||
);
|
||||
});
|
||||
|
||||
console.log('\n' + '='.repeat(100) + '\n');
|
||||
|
||||
61
node_modules/less/scripts/postinstall.js
generated
vendored
Normal file
61
node_modules/less/scripts/postinstall.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Post-install script for Less.js package
|
||||
*
|
||||
* This script installs Playwright browsers only when:
|
||||
* 1. This is a development environment (not when installed as a dependency)
|
||||
* 2. We're in a monorepo context (parent package.json exists)
|
||||
* 3. Not running in CI or other automated environments
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
// Check if we're in a development environment
|
||||
function isDevelopmentEnvironment() {
|
||||
// Skip if this is a global install or user config
|
||||
if (process.env.npm_config_user_config || process.env.npm_config_global) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip in CI environments
|
||||
if (process.env.CI || process.env.GITHUB_ACTIONS || process.env.TRAVIS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're in a monorepo (parent package.json exists)
|
||||
const parentPackageJson = path.join(__dirname, '../../../package.json');
|
||||
if (!fs.existsSync(parentPackageJson)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if this is the root of the monorepo
|
||||
const currentPackageJson = path.join(__dirname, '../package.json');
|
||||
if (!fs.existsSync(currentPackageJson)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Install Playwright browsers
|
||||
function installPlaywrightBrowsers() {
|
||||
try {
|
||||
console.log('🎭 Installing Playwright browsers for development...');
|
||||
execSync('pnpm exec playwright install', {
|
||||
stdio: 'inherit',
|
||||
cwd: path.join(__dirname, '..')
|
||||
});
|
||||
console.log('✅ Playwright browsers installed successfully');
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Failed to install Playwright browsers:', error.message);
|
||||
console.warn(' You can install them manually with: pnpm exec playwright install');
|
||||
}
|
||||
}
|
||||
|
||||
// Main execution
|
||||
if (isDevelopmentEnvironment()) {
|
||||
installPlaywrightBrowsers();
|
||||
}
|
||||
Reference in New Issue
Block a user