Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cspell-dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,4 @@ LTWH
blockquotes
Blockquotes
strikethrough
unconfigured
10 changes: 0 additions & 10 deletions packages/dart_jsx/CHANGELOG.md

This file was deleted.

48 changes: 1 addition & 47 deletions tools/build/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,7 @@ String? _searchEntryPoints(String exampleDir, List<String> remaining) {
);
}

// Transpile JSX files before compilation
final jsxResult = _transpileJsxFiles(exampleDir);
return !jsxResult.isSuccess
? jsxResult
: _compileToJs(exampleDir, entryPoint, target, buildDir);
return _compileToJs(exampleDir, entryPoint, target, buildDir);
}

({bool isSuccess, String message}) _compileToJs(
Expand Down Expand Up @@ -252,45 +248,3 @@ String? _searchEntryPoints(String exampleDir, List<String> remaining) {
print(' Build complete: $finalOutput');
return (isSuccess: true, message: 'Build successful');
}

({bool isSuccess, String message}) _transpileJsxFiles(String exampleDir) {
final dir = Directory(exampleDir);
final jsxFiles = dir
.listSync(recursive: true)
.whereType<File>()
.where((f) => f.path.endsWith('.jsx'))
.toList();

final hasJsxFiles = jsxFiles.isNotEmpty;
if (!hasJsxFiles) {
return (isSuccess: true, message: 'No JSX files to transpile');
}

print(' Transpiling ${jsxFiles.length} JSX file(s)...');

for (final file in jsxFiles) {
final result = _transpileJsxFile(file.path);
if (!result.isSuccess) return result;
}

return (isSuccess: true, message: 'JSX transpilation complete');
}

({bool isSuccess, String message}) _transpileJsxFile(String inputPath) {
final outputPath = inputPath.replaceAll('.jsx', '.g.dart');
final projectRoot = Directory.current.path;

final result = Process.runSync('dart', [
'run',
'$projectRoot/packages/dart_jsx/bin/jsx.dart',
inputPath,
outputPath,
]);

return result.exitCode != 0
? (
isSuccess: false,
message: 'JSX transpilation failed for $inputPath:\n${result.stderr}',
)
: (isSuccess: true, message: 'Transpiled $inputPath');
}
139 changes: 139 additions & 0 deletions tools/lib/packages.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// ignore_for_file: avoid_print
import 'dart:io';

/// Package metadata - single source of truth for all tooling
/// Dependencies are read from pubspec.yaml files
/// Test platforms and tiers are defined here
class PackageConfig {
final String name;
final int tier;
final TestPlatform testPlatform;
final bool publish;

const PackageConfig({
required this.name,
required this.tier,
required this.testPlatform,
this.publish = true,
});
}

enum TestPlatform { node, vm, browser }

/// Package configurations - defines tier, test platform, and publish status
/// Add new packages here when created
const _packageConfigs = <String, PackageConfig>{
// Tier 1 - no internal dependencies
'dart_logging': PackageConfig(
name: 'dart_logging',
tier: 1,
testPlatform: TestPlatform.vm,
),
'dart_node_core': PackageConfig(
name: 'dart_node_core',
tier: 1,
testPlatform: TestPlatform.node,
),
// Tier 2 - depends on tier 1
'reflux': PackageConfig(
name: 'reflux',
tier: 2,
testPlatform: TestPlatform.vm,
),
'dart_node_express': PackageConfig(
name: 'dart_node_express',
tier: 2,
testPlatform: TestPlatform.node,
),
'dart_node_ws': PackageConfig(
name: 'dart_node_ws',
tier: 2,
testPlatform: TestPlatform.node,
),
'dart_node_better_sqlite3': PackageConfig(
name: 'dart_node_better_sqlite3',
tier: 2,
testPlatform: TestPlatform.node,
),
'dart_node_mcp': PackageConfig(
name: 'dart_node_mcp',
tier: 2,
testPlatform: TestPlatform.node,
),
// Tier 3 - depends on tier 2
'dart_node_react': PackageConfig(
name: 'dart_node_react',
tier: 3,
testPlatform: TestPlatform.browser,
),
'dart_node_react_native': PackageConfig(
name: 'dart_node_react_native',
tier: 3,
testPlatform: TestPlatform.node,
),
// Non-published packages
'dart_node_coverage': PackageConfig(
name: 'dart_node_coverage',
tier: 0,
testPlatform: TestPlatform.vm,
publish: false,
),
};

/// Discovers packages from the filesystem that have pubspec.yaml
List<String> discoverPackages(String repoRoot) {
final packagesDir = Directory('$repoRoot/packages');
if (!packagesDir.existsSync()) return [];

return packagesDir
.listSync()
.whereType<Directory>()
.where((d) => File('${d.path}/pubspec.yaml').existsSync())
.map((d) => d.path.split('/').last)
.toList()
..sort();
}

/// Gets config for a package, returns null if not configured
PackageConfig? getPackageConfig(String name) => _packageConfigs[name];

/// Gets all publishable packages in tier order
List<PackageConfig> getPublishablePackages() {
final packages = _packageConfigs.values.where((p) => p.publish).toList()
..sort((a, b) {
final tierCmp = a.tier.compareTo(b.tier);
return tierCmp != 0 ? tierCmp : a.name.compareTo(b.name);
});
return packages;
}

/// Gets packages by tier
List<PackageConfig> getPackagesByTier(int tier) =>
_packageConfigs.values.where((p) => p.tier == tier && p.publish).toList();

/// Gets packages by test platform
List<PackageConfig> getPackagesByTestPlatform(TestPlatform platform) =>
_packageConfigs.values.where((p) => p.testPlatform == platform).toList();

/// Reads internal dependencies from a package's pubspec.yaml
/// Returns list of dependency names that are publishable internal packages
List<String> getInternalDependencies(String repoRoot, String packageName) {
final pubspecFile = File('$repoRoot/packages/$packageName/pubspec.yaml');
if (!pubspecFile.existsSync()) return [];

final content = pubspecFile.readAsStringSync();
final publishablePackages = getPublishablePackages()
.map((p) => p.name)
.toList();

return publishablePackages
.where((pkg) => pkg != packageName && content.contains('$pkg:'))
.toList();
}

/// Validates that all discovered packages have configs
/// Returns list of packages without configs
List<String> validatePackageConfigs(String repoRoot) {
final discovered = discoverPackages(repoRoot);
return discovered.where((p) => !_packageConfigs.containsKey(p)).toList();
}
59 changes: 19 additions & 40 deletions tools/prepare_publish.dart
Original file line number Diff line number Diff line change
@@ -1,40 +1,7 @@
// ignore_for_file: avoid_print
import 'dart:io';

/// Package dependency graph - order matters for publishing
/// Packages with no dependencies must be published first
const packageDeps = <String, List<String>>{
// Tier 1 - no internal dependencies
'dart_logging': [],
'dart_node_core': [],
'dart_jsx': [],
// Tier 2 - depends on tier 1
'reflux': ['dart_logging'],
'dart_node_express': ['dart_node_core'],
'dart_node_ws': ['dart_node_core'],
'dart_node_better_sqlite3': ['dart_node_core'],
'dart_node_mcp': ['dart_node_core'],
// Tier 3 - depends on tier 2
'dart_node_react': ['dart_node_core'],
'dart_node_react_native': ['dart_node_core', 'dart_node_react'],
};

/// Publishing order based on dependency graph (topological sort)
const publishOrder = [
// Tier 1
'dart_logging',
'dart_node_core',
'dart_jsx',
// Tier 2
'reflux',
'dart_node_express',
'dart_node_ws',
'dart_node_better_sqlite3',
'dart_node_mcp',
// Tier 3
'dart_node_react',
'dart_node_react_native',
];
import 'lib/packages.dart';

void main(List<String> args) {
if (args.isEmpty) {
Expand All @@ -56,20 +23,32 @@ void main(List<String> args) {
}

final scriptDir = File(Platform.script.toFilePath()).parent;
final repoRoot = scriptDir.parent;
final packagesDir = Directory('${repoRoot.path}/packages');
final repoRoot = scriptDir.parent.path;
final packagesDir = Directory('$repoRoot/packages');

// Validate all packages have configs
final unconfigured = validatePackageConfigs(repoRoot);
if (unconfigured.isNotEmpty) {
print('Warning: Packages without config (will be skipped):');
for (final pkg in unconfigured) {
print(' - $pkg');
}
print('Add them to tools/lib/packages.dart if they should be published.\n');
}

print('Preparing packages for publishing version $version\n');

for (final packageName in publishOrder) {
_preparePackage(packagesDir, packageName, version);
final packages = getPublishablePackages();
for (final pkg in packages) {
_preparePackage(repoRoot, packagesDir, pkg.name, version);
}

print('\nAll packages prepared for publishing!');
print('Publishing order: ${publishOrder.join(' -> ')}');
print('Publishing order: ${packages.map((p) => p.name).join(' -> ')}');
}

void _preparePackage(
String repoRoot,
Directory packagesDir,
String packageName,
String version,
Expand Down Expand Up @@ -98,7 +77,7 @@ void _preparePackage(
}

// 3. Update interdependencies to pub.dev versions
final deps = packageDeps[packageName] ?? [];
final deps = getInternalDependencies(repoRoot, packageName);
for (final dep in deps) {
content = _switchToPubDevDependency(content, dep, version);
changes.add('$dep -> $version');
Expand Down
Loading