forked from mirrors/material_3_expressive
- Introduced `.gitignore` and `.metadata` for apps and examples. - Added Flutter/Dart analysis configurations (`analysis_options.yaml`). - Implemented foundational tokens and themes for M3E (colors, shapes). - Created base implementations for `IconButtonM3E` and `SplitButtonM3E`. - Set up CI workflow (`ci.yaml`) to automate testing and analysis.
172 lines
5.3 KiB
Dart
172 lines
5.3 KiB
Dart
import 'dart:io';
|
|
|
|
String _pascal(String s) => s
|
|
.split('_')
|
|
.map((p) => p.isEmpty ? '' : (p[0].toUpperCase() + p.substring(1)))
|
|
.join();
|
|
|
|
void _ensureCollectionExport(String pkg) {
|
|
final path = 'packages/m3e_collection/lib/m3e_collection.dart';
|
|
final file = File(path);
|
|
if (!file.existsSync()) return;
|
|
final content = file.readAsStringSync();
|
|
final exportLine = "export 'package:$pkg/$pkg.dart';";
|
|
if (content.contains(exportLine)) return;
|
|
|
|
// Append the export line at the end, preserving a trailing newline.
|
|
final updated = content.trimRight() + '\n' + exportLine + '\n';
|
|
file.writeAsStringSync(updated);
|
|
}
|
|
|
|
void _ensureCollectionDependency(String pkg) {
|
|
final path = 'packages/m3e_collection/pubspec.yaml';
|
|
final file = File(path);
|
|
if (!file.existsSync()) return;
|
|
final content = file.readAsStringSync();
|
|
|
|
// If dependency already present, skip.
|
|
final keyPattern =
|
|
RegExp(r'^\s*' + RegExp.escape(pkg) + r'\s*:', multiLine: true);
|
|
if (keyPattern.hasMatch(content)) return;
|
|
|
|
// Ensure we are within dependencies block. If the file contains a dependencies: section,
|
|
// we can safely append additional two-space indented entries at EOF since there is no
|
|
// subsequent top-level section in the current file structure.
|
|
if (!content.contains(RegExp(r'^dependencies:\s*$', multiLine: true))) {
|
|
stderr.writeln(
|
|
'Warning: packages/m3e_collection/pubspec.yaml has no dependencies section; skipping adding $pkg.');
|
|
return;
|
|
}
|
|
|
|
final addition = ' $pkg:\n path: ../$pkg\n';
|
|
final updated = content.trimRight() + '\n' + addition + '\n';
|
|
file.writeAsStringSync(updated);
|
|
}
|
|
|
|
void _ensureCollectionOverride(String pkg) {
|
|
final path = 'packages/m3e_collection/pubspec_overrides.yaml';
|
|
final file = File(path);
|
|
if (!file.existsSync()) return;
|
|
var content = file.readAsStringSync();
|
|
|
|
// If override already present, skip.
|
|
final keyPattern =
|
|
RegExp(r'^\s*' + RegExp.escape(pkg) + r'\s*:', multiLine: true);
|
|
if (keyPattern.hasMatch(content)) return;
|
|
|
|
// Update the melos managed header list if present.
|
|
final headerRe = RegExp(r'^(#\s*melos_managed_dependency_overrides:\s*)(.*)$',
|
|
multiLine: true);
|
|
content = content.replaceFirstMapped(headerRe, (m) {
|
|
final prefix = m.group(1)!;
|
|
final list = m.group(2)!.trim();
|
|
if (list.isEmpty) return '${prefix}$pkg';
|
|
final items = list.split(',').map((s) => s.trim()).toList();
|
|
if (!items.contains(pkg)) {
|
|
items.add(pkg);
|
|
}
|
|
return prefix + items.join(',');
|
|
});
|
|
|
|
// Ensure dependency_overrides: section exists; if not, create it.
|
|
if (!content
|
|
.contains(RegExp(r'^dependency_overrides:\s*$', multiLine: true))) {
|
|
if (!content.endsWith('\n')) content += '\n';
|
|
content += 'dependency_overrides:\n';
|
|
}
|
|
|
|
// Append our override using Windows-style path to match existing file style.
|
|
final addition = ' $pkg:\n path: ..\\$pkg\n';
|
|
content = content.trimRight() + '\n' + addition + '\n';
|
|
file.writeAsStringSync(content);
|
|
}
|
|
|
|
void main(List<String> args) async {
|
|
final nameArg =
|
|
args.firstWhere((a) => a.startsWith('name='), orElse: () => 'name=');
|
|
final name = nameArg.split('=').last;
|
|
if (name.isEmpty) {
|
|
stderr.writeln(
|
|
'Usage: melos run create -- name=<component> (_m3e suffix added automatically)');
|
|
exit(64);
|
|
}
|
|
final pkg = '${name}_m3e';
|
|
final dir = Directory('packages/$pkg');
|
|
if (dir.existsSync()) {
|
|
stderr.writeln('Package $pkg already exists.');
|
|
exit(1);
|
|
}
|
|
dir.createSync(recursive: true);
|
|
|
|
File('packages/$pkg/pubspec.yaml').writeAsStringSync('''
|
|
name: $pkg
|
|
description: $name (Material 3 Expressive)
|
|
version: 0.1.0
|
|
publish_to: none
|
|
|
|
environment:
|
|
sdk: ">=3.5.0 <4.0.0"
|
|
|
|
dependencies:
|
|
flutter:
|
|
sdk: flutter
|
|
m3e_design:
|
|
path: ../m3e_design
|
|
|
|
dev_dependencies:
|
|
flutter_test:
|
|
sdk: flutter
|
|
''');
|
|
|
|
Directory('packages/$pkg/lib').createSync();
|
|
File('packages/$pkg/lib/$pkg.dart').writeAsStringSync('''
|
|
library $pkg;
|
|
|
|
// TODO: implement $name M3E widget
|
|
export 'src/${name}_m3e_widget.dart';
|
|
''');
|
|
|
|
Directory('packages/$pkg/lib/src').createSync();
|
|
File('packages/$pkg/lib/src/${name}_m3e_widget.dart').writeAsStringSync('''
|
|
import 'package:flutter/material.dart';
|
|
import 'package:m3e_design/m3e_design.dart';
|
|
|
|
class ${_pascal(name)}M3EWidget extends StatelessWidget {
|
|
const ${_pascal(name)}M3EWidget({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final m3e = context.m3e;
|
|
return Container(
|
|
padding: EdgeInsets.all(m3e.spacing.md),
|
|
decoration: BoxDecoration(
|
|
color: m3e.colors.surfaceStrong,
|
|
borderRadius: m3e.shapes.square.md,
|
|
),
|
|
child: Text('${_pascal(name)} placeholder', style: m3e.typography.base.titleMedium),
|
|
);
|
|
}
|
|
}
|
|
|
|
String _pascal(String s) => s.split('_').map((p) => p.isEmpty ? '' : (p[0].toUpperCase() + p.substring(1))).join();
|
|
''');
|
|
|
|
Directory('packages/$pkg/test').createSync();
|
|
File('packages/$pkg/test/${name}_m3e_test.dart').writeAsStringSync('''
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
test('placeholder', () {
|
|
expect(1 + 1, 2);
|
|
});
|
|
}
|
|
''');
|
|
|
|
// Also add this new package to the aggregated collection package.
|
|
_ensureCollectionExport(pkg);
|
|
_ensureCollectionDependency(pkg);
|
|
_ensureCollectionOverride(pkg);
|
|
|
|
stdout.writeln(
|
|
'Created packages/$pkg and updated m3e_collection to include it.');
|
|
}
|