mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-26 18:35:05 +00:00
Merge PR #3470: detect Dart and structurally identify Flutter dependencies
This commit is contained in:
2 files changed
+115
-2
No files matched your search
@@ -9,6 +9,7 @@
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
/**
|
||||
* Language detection rules.
|
||||
@@ -84,6 +85,11 @@ const LANGUAGE_RULES = [
|
||||
type: 'php',
|
||||
markers: ['composer.json', 'composer.lock'],
|
||||
extensions: ['.php']
|
||||
},
|
||||
{
|
||||
type: 'dart',
|
||||
markers: ['pubspec.yaml', 'pubspec.lock'],
|
||||
extensions: ['.dart']
|
||||
}
|
||||
];
|
||||
|
||||
@@ -129,7 +135,10 @@ const FRAMEWORK_RULES = [
|
||||
{ framework: 'symfony', language: 'php', markers: ['symfony.lock'], packageKeys: ['symfony/framework-bundle'] },
|
||||
|
||||
// Elixir frameworks
|
||||
{ framework: 'phoenix', language: 'elixir', markers: [], packageKeys: ['phoenix'] }
|
||||
{ framework: 'phoenix', language: 'elixir', markers: [], packageKeys: ['phoenix'] },
|
||||
|
||||
// Dart frameworks
|
||||
{ framework: 'flutter', language: 'dart', markers: [], packageKeys: [], customCheck: hasFlutterSdkDependency }
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -330,6 +339,27 @@ function getElixirDeps(projectDir) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether pubspec.yaml declares the Flutter SDK as a dependency,
|
||||
* which distinguishes a Flutter app from a plain Dart package.
|
||||
* @param {string} projectDir - Project root directory
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasFlutterSdkDependency(projectDir) {
|
||||
try {
|
||||
const pubspecPath = path.join(projectDir, 'pubspec.yaml');
|
||||
if (!fs.existsSync(pubspecPath)) return false;
|
||||
const content = fs.readFileSync(pubspecPath, 'utf8');
|
||||
const pubspec = yaml.load(content, { schema: yaml.JSON_SCHEMA });
|
||||
// Only a declared Flutter SDK dependency identifies the framework.
|
||||
// Unrelated configuration, comments, and strings must not count.
|
||||
return pubspec?.dependencies?.flutter?.sdk === 'flutter'
|
||||
|| pubspec?.dev_dependencies?.flutter?.sdk === 'flutter';
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect project languages and frameworks
|
||||
* @param {string} [projectDir] - Project directory (defaults to cwd)
|
||||
@@ -409,7 +439,9 @@ function detectProjectType(projectDir) {
|
||||
});
|
||||
}
|
||||
|
||||
if (hasMarker || hasDep) {
|
||||
const hasCustom = typeof rule.customCheck === 'function' ? rule.customCheck(projectDir) : false;
|
||||
|
||||
if (hasMarker || hasDep || hasCustom) {
|
||||
frameworks.push(rule.framework);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,6 +493,87 @@ function runTests() {
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
// Dart/Flutter detection
|
||||
console.log('\nDart/Flutter Detection:');
|
||||
|
||||
if (test('detects dart from pubspec.yaml and .dart files', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', 'name: test_pkg\nversion: 1.0.0\n');
|
||||
writeTestFile(dir, 'main.dart', 'void main() {}\n');
|
||||
const result = detectProjectType(dir);
|
||||
assert.ok(result.languages.includes('dart'));
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('detects flutter framework when pubspec.yaml depends on the Flutter SDK', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', [
|
||||
'name: halal_cosmetics_app',
|
||||
'dependencies:',
|
||||
' flutter:',
|
||||
' sdk: flutter',
|
||||
' cupertino_icons: ^1.0.2'
|
||||
].join('\n'));
|
||||
const result = detectProjectType(dir);
|
||||
assert.ok(result.languages.includes('dart'));
|
||||
assert.ok(result.frameworks.includes('flutter'), `flutter not detected: ${JSON.stringify(result.frameworks)}`);
|
||||
assert.strictEqual(result.primary, 'flutter');
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('does not misclassify a plain Dart package as flutter', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', [
|
||||
'name: plain_dart_pkg',
|
||||
'dependencies:',
|
||||
' http: ^1.0.0'
|
||||
].join('\n'));
|
||||
const result = detectProjectType(dir);
|
||||
assert.ok(result.languages.includes('dart'));
|
||||
assert.ok(!result.frameworks.includes('flutter'), `plain Dart package wrongly detected as flutter: ${JSON.stringify(result.frameworks)}`);
|
||||
assert.strictEqual(result.primary, 'dart');
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('does not combine unrelated Flutter and SDK configuration', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', 'name: plain_dart\nflutter:\n assets: []\ndependencies:\n other:\n sdk: flutter\n');
|
||||
assert.ok(!detectProjectType(dir).frameworks.includes('flutter'));
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('detects inline Flutter SDK dependencies', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', 'name: flutter_pkg\ndependencies: {flutter: {sdk: flutter}}\n');
|
||||
assert.ok(detectProjectType(dir).frameworks.includes('flutter'));
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
if (test('malformed pubspec does not claim Flutter detection', () => {
|
||||
const dir = createTempDir();
|
||||
try {
|
||||
writeTestFile(dir, 'pubspec.yaml', 'dependencies: [\nflutter:\n sdk: flutter\n');
|
||||
assert.ok(!detectProjectType(dir).frameworks.includes('flutter'));
|
||||
} finally {
|
||||
cleanupDir(dir);
|
||||
}
|
||||
})) passed++; else failed++;
|
||||
|
||||
// Edge cases
|
||||
console.log('\nEdge Cases:');
|
||||
|
||||
|
||||
Reference in new issue
Block a user