From d942a8679b0af10211b759635933af987cbca28f Mon Sep 17 00:00:00 2001 From: Mensch Date: Mon, 6 Mar 2023 19:17:03 +0500 Subject: [PATCH 01/11] Create initial dart project --- dart/.gitignore | 7 +++++ dart/CHANGELOG.md | 3 +++ dart/README.md | 39 +++++++++++++++++++++++++++ dart/analysis_options.yaml | 30 +++++++++++++++++++++ dart/example/minify_html_example.dart | 6 +++++ dart/lib/minify_html.dart | 8 ++++++ dart/lib/src/minify_html_base.dart | 6 +++++ dart/native/Cargo.toml | 8 ++++++ dart/native/src/lib.rs | 14 ++++++++++ dart/pubspec.yaml | 14 ++++++++++ dart/test/minify_html_test.dart | 16 +++++++++++ 11 files changed, 151 insertions(+) create mode 100644 dart/.gitignore create mode 100644 dart/CHANGELOG.md create mode 100644 dart/README.md create mode 100644 dart/analysis_options.yaml create mode 100644 dart/example/minify_html_example.dart create mode 100644 dart/lib/minify_html.dart create mode 100644 dart/lib/src/minify_html_base.dart create mode 100644 dart/native/Cargo.toml create mode 100644 dart/native/src/lib.rs create mode 100644 dart/pubspec.yaml create mode 100644 dart/test/minify_html_test.dart diff --git a/dart/.gitignore b/dart/.gitignore new file mode 100644 index 00000000..3cceda55 --- /dev/null +++ b/dart/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/dart/CHANGELOG.md b/dart/CHANGELOG.md new file mode 100644 index 00000000..effe43c8 --- /dev/null +++ b/dart/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/dart/README.md b/dart/README.md new file mode 100644 index 00000000..8b55e735 --- /dev/null +++ b/dart/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/dart/analysis_options.yaml b/dart/analysis_options.yaml new file mode 100644 index 00000000..dee8927a --- /dev/null +++ b/dart/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/dart/example/minify_html_example.dart b/dart/example/minify_html_example.dart new file mode 100644 index 00000000..b09aa4ce --- /dev/null +++ b/dart/example/minify_html_example.dart @@ -0,0 +1,6 @@ +import 'package:minify_html/minify_html.dart'; + +void main() { + var awesome = Awesome(); + print('awesome: ${awesome.isAwesome}'); +} diff --git a/dart/lib/minify_html.dart b/dart/lib/minify_html.dart new file mode 100644 index 00000000..f2f0f5af --- /dev/null +++ b/dart/lib/minify_html.dart @@ -0,0 +1,8 @@ +/// Support for doing something awesome. +/// +/// More dartdocs go here. +library minify_html; + +export 'src/minify_html_base.dart'; + +// TODO: Export any libraries intended for clients of this package. diff --git a/dart/lib/src/minify_html_base.dart b/dart/lib/src/minify_html_base.dart new file mode 100644 index 00000000..e8a6f159 --- /dev/null +++ b/dart/lib/src/minify_html_base.dart @@ -0,0 +1,6 @@ +// TODO: Put public facing types in this file. + +/// Checks if you are awesome. Spoiler: you are. +class Awesome { + bool get isAwesome => true; +} diff --git a/dart/native/Cargo.toml b/dart/native/Cargo.toml new file mode 100644 index 00000000..66a8d3e4 --- /dev/null +++ b/dart/native/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "native" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/dart/native/src/lib.rs b/dart/native/src/lib.rs new file mode 100644 index 00000000..7d12d9af --- /dev/null +++ b/dart/native/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml new file mode 100644 index 00000000..c1c2a7f6 --- /dev/null +++ b/dart/pubspec.yaml @@ -0,0 +1,14 @@ +name: minify_html +description: A starting point for Dart libraries or applications. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: '>=2.19.2 <3.0.0' + +# dependencies: +# path: ^1.8.0 + +dev_dependencies: + lints: ^2.0.0 + test: ^1.21.0 diff --git a/dart/test/minify_html_test.dart b/dart/test/minify_html_test.dart new file mode 100644 index 00000000..9a461720 --- /dev/null +++ b/dart/test/minify_html_test.dart @@ -0,0 +1,16 @@ +import 'package:minify_html/minify_html.dart'; +import 'package:test/test.dart'; + +void main() { + group('A group of tests', () { + final awesome = Awesome(); + + setUp(() { + // Additional setup goes here. + }); + + test('First Test', () { + expect(awesome.isAwesome, isTrue); + }); + }); +} From 6af6286f0a31968d5426128cfb9fec231f974d21 Mon Sep 17 00:00:00 2001 From: Mensch Date: Mon, 6 Mar 2023 19:35:54 +0500 Subject: [PATCH 02/11] Add rust extern minify function --- dart/native/.gitignore | 2 ++ dart/native/Cargo.toml | 6 ++++- dart/native/src/lib.rs | 50 ++++++++++++++++++++++++++++++++---------- 3 files changed, 46 insertions(+), 12 deletions(-) create mode 100644 dart/native/.gitignore diff --git a/dart/native/.gitignore b/dart/native/.gitignore new file mode 100644 index 00000000..869df07d --- /dev/null +++ b/dart/native/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/dart/native/Cargo.toml b/dart/native/Cargo.toml index 66a8d3e4..4296b243 100644 --- a/dart/native/Cargo.toml +++ b/dart/native/Cargo.toml @@ -1,8 +1,12 @@ [package] -name = "native" +name = "minify-html-native" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "minifyhtml" +crate-type = ["cdylib"] [dependencies] +minify-html = { version = "0.10.8", path = "../../rust/main" } diff --git a/dart/native/src/lib.rs b/dart/native/src/lib.rs index 7d12d9af..fd92176b 100644 --- a/dart/native/src/lib.rs +++ b/dart/native/src/lib.rs @@ -1,14 +1,42 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} +use std::slice; + +use minify_html::Cfg; + +#[no_mangle] +pub extern "C" fn minify_html( + input: *const u8, + length: usize, + do_not_minify_doctype: bool, + ensure_spec_compliant_unquoted_attribute_values: bool, + keep_closing_tags: bool, + keep_html_and_head_opening_tags: bool, + keep_spaces_between_attributes: bool, + keep_comments: bool, + minify_css: bool, + minify_css_level_1: bool, + minify_css_level_2: bool, + minify_css_level_3: bool, + minify_js: bool, + remove_bangs: bool, + remove_processing_instructions: bool, +) { + let src = unsafe { slice::from_raw_parts(input, length) }; -#[cfg(test)] -mod tests { - use super::*; + let cfg = Cfg { + do_not_minify_doctype, + ensure_spec_compliant_unquoted_attribute_values, + keep_closing_tags, + keep_html_and_head_opening_tags, + keep_spaces_between_attributes, + keep_comments, + minify_css, + minify_css_level_1, + minify_css_level_2, + minify_css_level_3, + minify_js, + remove_bangs, + remove_processing_instructions, + }; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } + minify_html::minify(src, &cfg); } From 8876f98d229e6f5852f7def0fc6b6f561fedc02e Mon Sep 17 00:00:00 2001 From: Mensch Date: Mon, 6 Mar 2023 20:14:56 +0500 Subject: [PATCH 03/11] Write initial binding code for dart --- dart/example/minify_html_example.dart | 5 -- dart/lib/minify_html.dart | 7 --- dart/lib/src/bindings.dart | 57 +++++++++++++++++ dart/lib/src/locator.dart | 89 +++++++++++++++++++++++++++ dart/lib/src/minify_html.dart | 34 ++++++++++ dart/lib/src/minify_html_base.dart | 6 -- dart/lib/src/models.dart | 38 ++++++++++++ dart/lib/src/resource.dart | 37 +++++++++++ dart/pubspec.yaml | 4 +- dart/test/minify_html_test.dart | 16 ----- 10 files changed, 257 insertions(+), 36 deletions(-) create mode 100644 dart/lib/src/bindings.dart create mode 100644 dart/lib/src/locator.dart create mode 100644 dart/lib/src/minify_html.dart delete mode 100644 dart/lib/src/minify_html_base.dart create mode 100644 dart/lib/src/models.dart create mode 100644 dart/lib/src/resource.dart delete mode 100644 dart/test/minify_html_test.dart diff --git a/dart/example/minify_html_example.dart b/dart/example/minify_html_example.dart index b09aa4ce..8b137891 100644 --- a/dart/example/minify_html_example.dart +++ b/dart/example/minify_html_example.dart @@ -1,6 +1 @@ -import 'package:minify_html/minify_html.dart'; -void main() { - var awesome = Awesome(); - print('awesome: ${awesome.isAwesome}'); -} diff --git a/dart/lib/minify_html.dart b/dart/lib/minify_html.dart index f2f0f5af..0893db03 100644 --- a/dart/lib/minify_html.dart +++ b/dart/lib/minify_html.dart @@ -1,8 +1 @@ -/// Support for doing something awesome. -/// -/// More dartdocs go here. library minify_html; - -export 'src/minify_html_base.dart'; - -// TODO: Export any libraries intended for clients of this package. diff --git a/dart/lib/src/bindings.dart b/dart/lib/src/bindings.dart new file mode 100644 index 00000000..5dba52d8 --- /dev/null +++ b/dart/lib/src/bindings.dart @@ -0,0 +1,57 @@ +// ignore_for_file: non_constant_identifier_names, camel_case_types + +import 'dart:ffi'; + +import 'package:ffi/ffi.dart'; +import 'package:minify_html/src/locator.dart'; + +typedef minify_html_native = Int32 Function( + Pointer input, + Uint32 length, + Bool do_not_minify_doctype, + Bool ensure_spec_compliant_unquoted_attribute_values, + Bool keep_closing_tags, + Bool keep_html_and_head_opening_tags, + Bool keep_spaces_between_attributes, + Bool keep_comments, + Bool minify_css, + Bool minify_css_level_1, + Bool minify_css_level_2, + Bool minify_css_level_3, + Bool minify_js, + Bool remove_bangs, + Bool remove_processing_instructions, +); + +class MinifyHtmlBindings { + late DynamicLibrary _library; + + late int Function( + Pointer input, + int length, + bool do_not_minify_doctype, + bool ensure_spec_compliant_unquoted_attribute_values, + bool keep_closing_tags, + bool keep_html_and_head_opening_tags, + bool keep_spaces_between_attributes, + bool keep_comments, + bool minify_css, + bool minify_css_level_1, + bool minify_css_level_2, + bool minify_css_level_3, + bool minify_js, + bool remove_bangs, + bool remove_processing_instructions, + ) minifyHtml; + + MinifyHtmlBindings() { + _library = loadDynamicLibrary(); + + minifyHtml = _library + .lookup>("minify_html") + .asFunction(); + } +} + +MinifyHtmlBindings? _cachedBindings; +MinifyHtmlBindings get bindings => _cachedBindings ??= MinifyHtmlBindings(); diff --git a/dart/lib/src/locator.dart b/dart/lib/src/locator.dart new file mode 100644 index 00000000..6029f7cf --- /dev/null +++ b/dart/lib/src/locator.dart @@ -0,0 +1,89 @@ +import 'dart:ffi'; +import 'dart:io'; + +/// Attempts to locate the MinifyHtml dynamic library. +/// +/// Throws [MinifyHtmlLocatorError] if the dynamic library could not be found. +DynamicLibrary loadDynamicLibrary() { + String locate(String libName) { + final dir = '$_minifyhtmlToolDir$libName'; + final value = _packageRootUri(Platform.script.resolve('./')) ?? + _packageRootUri(Directory.current.uri); + if (value != null) { + return value.resolve(dir).toFilePath(); + } else { + throw MinifyHtmlLocatorError( + 'MinifyHtml library not found. Did you run `$invocationString`?', + ); + } + } + + if (Platform.isIOS) { + return DynamicLibrary.process(); + } else if (Platform.isMacOS) { + return DynamicLibrary.open(locate(appleLib)); + } else if (Platform.isWindows) { + return DynamicLibrary.open(locate(windowsLib)); + } else if (Platform.isLinux) { + return DynamicLibrary.open(locate(linuxLib)); + } else if (Platform.isAndroid) { + return DynamicLibrary.open(linuxLib); + } else if (Platform.isFuchsia) { + throw MinifyHtmlLocatorError( + 'MinifyHtml is currently not supported on Fuchsia.', + ); + } else { + throw MinifyHtmlLocatorError( + 'MinifyHtml is currently not supported on this platform.', + ); + } +} + +/// This error is thrown when the dynamic library could not be found. +class MinifyHtmlLocatorError extends Error { + final String message; + + MinifyHtmlLocatorError( + this.message, + ); + + @override + String toString() => 'MinifyHtmlLocatorError: $message'; +} + +/// The command that can be used to set up this package. +const invocationString = 'dart run minifyhtml:setup'; + +/// The expected name of the MinifyHtml library when compiled for Apple devices. +const appleLib = 'libminifyhtml.dylib'; + +/// The expected name of the MinifyHtml library when compiled for Linux devices. +const linuxLib = 'libminifyhtml.so'; + +/// The expected name of the MinifyHtml library when compiled for Windows devices. +const windowsLib = 'minifyhtml.dll'; + +/// Returns the uri representing the target output directory of generated +/// dynamic libraries. +Uri libBuildOutDir(Uri root) { + final pkgRoot = _packageRootUri(root); + if (pkgRoot == null) { + throw ArgumentError('Could not find "$_pkgConfigFile" within "$root".'); + } + return pkgRoot.resolve(_minifyhtmlToolDir); +} + +const _minifyhtmlToolDir = '.dart_tool/minifyhtml/'; + +const _pkgConfigFile = '.dart_tool/package_config.json'; + +Uri? _packageRootUri(Uri root) { + do { + if (FileSystemEntity.isFileSync( + root.resolve(_pkgConfigFile).toFilePath(), + )) { + return root; + } + } while (root != (root = root.resolve('..'))); + return null; +} diff --git a/dart/lib/src/minify_html.dart b/dart/lib/src/minify_html.dart new file mode 100644 index 00000000..887d4f5c --- /dev/null +++ b/dart/lib/src/minify_html.dart @@ -0,0 +1,34 @@ +import 'package:ffi/ffi.dart'; +import 'package:minify_html/src/bindings.dart'; +import 'package:minify_html/src/models.dart'; +import 'package:minify_html/src/resource.dart'; + +String minifyHtml(String source, [Cfg? cfg]) { + cfg = cfg ??= Cfg(); + + final srcC = Utf8Resource(source); + + try { + final length = bindings.minifyHtml( + srcC.unsafe(), + srcC.length, + cfg.doNotMinifyDoctype, + cfg.ensureSpecCompliantUnquotedAttributeValues, + cfg.keepClosingTags, + cfg.keepHtmlAndHeadOpeningTags, + cfg.keepSpacesBetweenAttributes, + cfg.keepComments, + cfg.minifyCss, + cfg.minifyCssLevel1, + cfg.minifyCssLevel2, + cfg.minifyCssLevel3, + cfg.minifyJs, + cfg.removeBangs, + cfg.removeProcessingInstructions, + ); + + return ""; + } finally { + srcC.free(); + } +} diff --git a/dart/lib/src/minify_html_base.dart b/dart/lib/src/minify_html_base.dart deleted file mode 100644 index e8a6f159..00000000 --- a/dart/lib/src/minify_html_base.dart +++ /dev/null @@ -1,6 +0,0 @@ -// TODO: Put public facing types in this file. - -/// Checks if you are awesome. Spoiler: you are. -class Awesome { - bool get isAwesome => true; -} diff --git a/dart/lib/src/models.dart b/dart/lib/src/models.dart new file mode 100644 index 00000000..4cbd1154 --- /dev/null +++ b/dart/lib/src/models.dart @@ -0,0 +1,38 @@ +class Cfg { + const Cfg({ + this.doNotMinifyDoctype = false, + this.ensureSpecCompliantUnquotedAttributeValues = false, + this.keepClosingTags = false, + this.keepHtmlAndHeadOpeningTags = false, + this.keepSpacesBetweenAttributes = false, + this.keepComments = false, + this.minifyCss = false, + this.minifyCssLevel1 = false, + this.minifyCssLevel2 = false, + this.minifyCssLevel3 = false, + this.minifyJs = false, + this.removeBangs = false, + this.removeProcessingInstructions = false, + }); + + const Cfg.specCompliant() + : this( + doNotMinifyDoctype: true, + ensureSpecCompliantUnquotedAttributeValues: true, + keepSpacesBetweenAttributes: true, + ); + + final bool doNotMinifyDoctype; + final bool ensureSpecCompliantUnquotedAttributeValues; + final bool keepClosingTags; + final bool keepHtmlAndHeadOpeningTags; + final bool keepSpacesBetweenAttributes; + final bool keepComments; + final bool minifyCss; + final bool minifyCssLevel1; + final bool minifyCssLevel2; + final bool minifyCssLevel3; + final bool minifyJs; + final bool removeBangs; + final bool removeProcessingInstructions; +} diff --git a/dart/lib/src/resource.dart b/dart/lib/src/resource.dart new file mode 100644 index 00000000..462b158b --- /dev/null +++ b/dart/lib/src/resource.dart @@ -0,0 +1,37 @@ +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:typed_data'; + +import 'package:ffi/ffi.dart'; + +final DynamicLibrary stdlib = DynamicLibrary.process(); +final posixFree = stdlib.lookup>("free"); + +class Utf8Resource implements Finalizable { + static final NativeFinalizer _finalizer = NativeFinalizer(posixFree); + + /// [_cString] must never escape [Utf8Resource], otherwise the + /// [_finalizer] will run prematurely. + late final Pointer _cString; + late final int length; + + Utf8Resource(String source) { + final units = utf8.encode(source); + length = units.length; + + final Pointer result = malloc(units.length + 1); + final Uint8List nativeString = result.asTypedList(units.length + 1); + nativeString.setAll(0, units); + _cString = result.cast(); + + _finalizer.attach(this, _cString.cast(), detach: this); + } + + void free() { + _finalizer.detach(this); + calloc.free(_cString); + } + + /// Ensure this [Utf8Resource] stays in scope longer than the inner resource. + Pointer unsafe() => _cString; +} diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index c1c2a7f6..bbf0cd82 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -6,8 +6,8 @@ version: 1.0.0 environment: sdk: '>=2.19.2 <3.0.0' -# dependencies: -# path: ^1.8.0 +dependencies: + ffi: ^2.0.1 dev_dependencies: lints: ^2.0.0 diff --git a/dart/test/minify_html_test.dart b/dart/test/minify_html_test.dart deleted file mode 100644 index 9a461720..00000000 --- a/dart/test/minify_html_test.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:minify_html/minify_html.dart'; -import 'package:test/test.dart'; - -void main() { - group('A group of tests', () { - final awesome = Awesome(); - - setUp(() { - // Additional setup goes here. - }); - - test('First Test', () { - expect(awesome.isAwesome, isTrue); - }); - }); -} From 8101ce5ce0ad6dc649963a0873c1aa28008da489 Mon Sep 17 00:00:00 2001 From: Mensch Date: Mon, 6 Mar 2023 21:34:11 +0500 Subject: [PATCH 04/11] Return and parse utf8 string with length --- dart/lib/minify_html.dart | 2 ++ dart/lib/src/bindings.dart | 14 ++++++++++++++ dart/lib/src/minify_html.dart | 5 ++++- dart/native/src/lib.rs | 27 ++++++++++++++++++++++++--- dart/pubspec.yaml | 4 ++-- dart/test/minify_html_test.dart | 11 +++++++++++ 6 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 dart/test/minify_html_test.dart diff --git a/dart/lib/minify_html.dart b/dart/lib/minify_html.dart index 0893db03..99d12d1e 100644 --- a/dart/lib/minify_html.dart +++ b/dart/lib/minify_html.dart @@ -1 +1,3 @@ library minify_html; + +export 'src/minify_html.dart'; diff --git a/dart/lib/src/bindings.dart b/dart/lib/src/bindings.dart index 5dba52d8..5d5bab3f 100644 --- a/dart/lib/src/bindings.dart +++ b/dart/lib/src/bindings.dart @@ -23,6 +23,10 @@ typedef minify_html_native = Int32 Function( Bool remove_processing_instructions, ); +typedef get_last_result_native = Pointer Function(); + +typedef clear_last_result_native = Void Function(); + class MinifyHtmlBindings { late DynamicLibrary _library; @@ -44,12 +48,22 @@ class MinifyHtmlBindings { bool remove_processing_instructions, ) minifyHtml; + late Pointer Function() getLastResult; + + late void Function() clearLastResult; + MinifyHtmlBindings() { _library = loadDynamicLibrary(); minifyHtml = _library .lookup>("minify_html") .asFunction(); + getLastResult = _library + .lookup>("get_last_result") + .asFunction(); + clearLastResult = _library + .lookup>("clear_last_result") + .asFunction(); } } diff --git a/dart/lib/src/minify_html.dart b/dart/lib/src/minify_html.dart index 887d4f5c..1e1c1a98 100644 --- a/dart/lib/src/minify_html.dart +++ b/dart/lib/src/minify_html.dart @@ -27,7 +27,10 @@ String minifyHtml(String source, [Cfg? cfg]) { cfg.removeProcessingInstructions, ); - return ""; + final value = bindings.getLastResult().toDartString(length: length); + bindings.clearLastResult(); + + return value; } finally { srcC.free(); } diff --git a/dart/native/src/lib.rs b/dart/native/src/lib.rs index fd92176b..b6bcafe6 100644 --- a/dart/native/src/lib.rs +++ b/dart/native/src/lib.rs @@ -1,7 +1,11 @@ -use std::slice; +use std::{cell::RefCell, ptr, slice}; use minify_html::Cfg; +thread_local! { + static LAST_RESULT: RefCell>> = RefCell::new(None); +} + #[no_mangle] pub extern "C" fn minify_html( input: *const u8, @@ -19,7 +23,7 @@ pub extern "C" fn minify_html( minify_js: bool, remove_bangs: bool, remove_processing_instructions: bool, -) { +) -> usize { let src = unsafe { slice::from_raw_parts(input, length) }; let cfg = Cfg { @@ -38,5 +42,22 @@ pub extern "C" fn minify_html( remove_processing_instructions, }; - minify_html::minify(src, &cfg); + let result = minify_html::minify(src, &cfg); + let len = result.len(); + + LAST_RESULT.with(|v| *v.borrow_mut() = Some(result)); + len +} + +#[no_mangle] +pub extern "C" fn get_last_result() -> *const u8 { + LAST_RESULT.with(|prev| match prev.borrow().as_ref() { + Some(bytes) => bytes.as_ptr(), + None => return ptr::null(), + }) +} + +#[no_mangle] +pub extern "C" fn clear_last_result() { + LAST_RESULT.with(|value| *value.borrow_mut() = None) } diff --git a/dart/pubspec.yaml b/dart/pubspec.yaml index bbf0cd82..b134379e 100644 --- a/dart/pubspec.yaml +++ b/dart/pubspec.yaml @@ -1,6 +1,6 @@ name: minify_html -description: A starting point for Dart libraries or applications. -version: 1.0.0 +description: Extremely fast and smart HTML + JS + CSS minifier +version: 0.10.8 # repository: https://github.com/my_org/my_repo environment: diff --git a/dart/test/minify_html_test.dart b/dart/test/minify_html_test.dart new file mode 100644 index 00000000..0238678f --- /dev/null +++ b/dart/test/minify_html_test.dart @@ -0,0 +1,11 @@ +import 'package:minify_html/minify_html.dart'; +import 'package:test/test.dart'; + +void main() { + test("should minify html", () { + expect( + minifyHtml("

Hello World!

"), + "

Hello World!", + ); + }); +} From b4702394d00133778e2f71523a7f761c497d687f Mon Sep 17 00:00:00 2001 From: Mensch Date: Mon, 6 Mar 2023 21:47:49 +0500 Subject: [PATCH 05/11] Add dart example --- dart/example/minify_html_example.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dart/example/minify_html_example.dart b/dart/example/minify_html_example.dart index 8b137891..e39e38a3 100644 --- a/dart/example/minify_html_example.dart +++ b/dart/example/minify_html_example.dart @@ -1 +1,5 @@ +import 'package:minify_html/minify_html.dart'; +void main(List args) { + final minified = minifyHtml("

Hello, world!

"); +} From 75ca7a67f49a610ffadf2b07b6a2cf9c564c4c1f Mon Sep 17 00:00:00 2001 From: Mensch Date: Tue, 7 Mar 2023 18:09:40 +0500 Subject: [PATCH 06/11] Allocate only required length of memory --- dart/lib/src/resource.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/resource.dart b/dart/lib/src/resource.dart index 462b158b..9beadefb 100644 --- a/dart/lib/src/resource.dart +++ b/dart/lib/src/resource.dart @@ -19,8 +19,8 @@ class Utf8Resource implements Finalizable { final units = utf8.encode(source); length = units.length; - final Pointer result = malloc(units.length + 1); - final Uint8List nativeString = result.asTypedList(units.length + 1); + final Pointer result = malloc(units.length); + final Uint8List nativeString = result.asTypedList(units.length); nativeString.setAll(0, units); _cString = result.cast(); From 46a08d44f0964a33e002bac07acedf3d5f5c6be4 Mon Sep 17 00:00:00 2001 From: Mensch Date: Tue, 7 Mar 2023 18:23:03 +0500 Subject: [PATCH 07/11] Remove unused libBuildOutDir function --- dart/lib/src/locator.dart | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/dart/lib/src/locator.dart b/dart/lib/src/locator.dart index 6029f7cf..d238a4ce 100644 --- a/dart/lib/src/locator.dart +++ b/dart/lib/src/locator.dart @@ -63,22 +63,13 @@ const linuxLib = 'libminifyhtml.so'; /// The expected name of the MinifyHtml library when compiled for Windows devices. const windowsLib = 'minifyhtml.dll'; -/// Returns the uri representing the target output directory of generated -/// dynamic libraries. -Uri libBuildOutDir(Uri root) { - final pkgRoot = _packageRootUri(root); - if (pkgRoot == null) { - throw ArgumentError('Could not find "$_pkgConfigFile" within "$root".'); - } - return pkgRoot.resolve(_minifyhtmlToolDir); -} - const _minifyhtmlToolDir = '.dart_tool/minifyhtml/'; const _pkgConfigFile = '.dart_tool/package_config.json'; Uri? _packageRootUri(Uri root) { do { + print(root); if (FileSystemEntity.isFileSync( root.resolve(_pkgConfigFile).toFilePath(), )) { From 23a46202be1d25c9dbf11cf7bfde0bad64b4ea10 Mon Sep 17 00:00:00 2001 From: Mensch Date: Tue, 7 Mar 2023 18:44:28 +0500 Subject: [PATCH 08/11] Delete changelog and readme --- dart/CHANGELOG.md | 3 --- dart/README.md | 39 --------------------------------------- 2 files changed, 42 deletions(-) delete mode 100644 dart/CHANGELOG.md delete mode 100644 dart/README.md diff --git a/dart/CHANGELOG.md b/dart/CHANGELOG.md deleted file mode 100644 index effe43c8..00000000 --- a/dart/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -## 1.0.0 - -- Initial version. diff --git a/dart/README.md b/dart/README.md deleted file mode 100644 index 8b55e735..00000000 --- a/dart/README.md +++ /dev/null @@ -1,39 +0,0 @@ - - -TODO: Put a short description of the package here that helps potential users -know whether this package might be useful for them. - -## Features - -TODO: List what your package can do. Maybe include images, gifs, or videos. - -## Getting started - -TODO: List prerequisites and provide or point to information on how to -start using the package. - -## Usage - -TODO: Include short and useful examples for package users. Add longer examples -to `/example` folder. - -```dart -const like = 'sample'; -``` - -## Additional information - -TODO: Tell users more about the package: where to find more information, how to -contribute to the package, how to file issues, what response they can expect -from the package authors, and more. From 182432a4cdf88f7007f42014f94287ae25dff9ca Mon Sep 17 00:00:00 2001 From: Mensch Date: Tue, 7 Mar 2023 19:12:32 +0500 Subject: [PATCH 09/11] Update locator to look for library in script directory and current directory and parents --- dart/lib/src/locator.dart | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/dart/lib/src/locator.dart b/dart/lib/src/locator.dart index d238a4ce..2da93b84 100644 --- a/dart/lib/src/locator.dart +++ b/dart/lib/src/locator.dart @@ -6,16 +6,22 @@ import 'dart:io'; /// Throws [MinifyHtmlLocatorError] if the dynamic library could not be found. DynamicLibrary loadDynamicLibrary() { String locate(String libName) { - final dir = '$_minifyhtmlToolDir$libName'; - final value = _packageRootUri(Platform.script.resolve('./')) ?? - _packageRootUri(Directory.current.uri); - if (value != null) { - return value.resolve(dir).toFilePath(); - } else { - throw MinifyHtmlLocatorError( - 'MinifyHtml library not found. Did you run `$invocationString`?', - ); + final path = _packageRootUri(Platform.script.resolve('./'), libName) ?? + _packageRootUri(Directory.current.uri, libName); + + if (path != null) { + return path; + } + + final toolLib = Directory.current.uri + .resolve("$_minifyhtmlToolDir$libName") + .toFilePath(); + + if (FileSystemEntity.isFileSync(toolLib)) { + return toolLib; } + + throw MinifyHtmlLocatorError('MinifyHtml library not found'); } if (Platform.isIOS) { @@ -65,15 +71,12 @@ const windowsLib = 'minifyhtml.dll'; const _minifyhtmlToolDir = '.dart_tool/minifyhtml/'; -const _pkgConfigFile = '.dart_tool/package_config.json'; - -Uri? _packageRootUri(Uri root) { +String? _packageRootUri(Uri root, String libName) { do { - print(root); - if (FileSystemEntity.isFileSync( - root.resolve(_pkgConfigFile).toFilePath(), - )) { - return root; + final filePath = root.resolve(libName).toFilePath(); + print(filePath); + if (FileSystemEntity.isFileSync(filePath)) { + return filePath; } } while (root != (root = root.resolve('..'))); return null; From da2fe6dfaab8724f1f812ded618b184494b912e2 Mon Sep 17 00:00:00 2001 From: Mensch Date: Tue, 7 Mar 2023 19:25:47 +0500 Subject: [PATCH 10/11] Remove print statement --- dart/lib/src/locator.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/dart/lib/src/locator.dart b/dart/lib/src/locator.dart index 2da93b84..b8cfc06e 100644 --- a/dart/lib/src/locator.dart +++ b/dart/lib/src/locator.dart @@ -74,7 +74,6 @@ const _minifyhtmlToolDir = '.dart_tool/minifyhtml/'; String? _packageRootUri(Uri root, String libName) { do { final filePath = root.resolve(libName).toFilePath(); - print(filePath); if (FileSystemEntity.isFileSync(filePath)) { return filePath; } From 5000d3430514476ef553424e73903b22bdb8305e Mon Sep 17 00:00:00 2001 From: Mensch Date: Fri, 10 Mar 2023 13:52:38 +0500 Subject: [PATCH 11/11] refactor: dont search parents for native library --- dart/lib/src/locator.dart | 52 +++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/dart/lib/src/locator.dart b/dart/lib/src/locator.dart index b8cfc06e..5341ad3a 100644 --- a/dart/lib/src/locator.dart +++ b/dart/lib/src/locator.dart @@ -5,33 +5,14 @@ import 'dart:io'; /// /// Throws [MinifyHtmlLocatorError] if the dynamic library could not be found. DynamicLibrary loadDynamicLibrary() { - String locate(String libName) { - final path = _packageRootUri(Platform.script.resolve('./'), libName) ?? - _packageRootUri(Directory.current.uri, libName); - - if (path != null) { - return path; - } - - final toolLib = Directory.current.uri - .resolve("$_minifyhtmlToolDir$libName") - .toFilePath(); - - if (FileSystemEntity.isFileSync(toolLib)) { - return toolLib; - } - - throw MinifyHtmlLocatorError('MinifyHtml library not found'); - } - if (Platform.isIOS) { return DynamicLibrary.process(); } else if (Platform.isMacOS) { - return DynamicLibrary.open(locate(appleLib)); + return _locateOrError(appleLib); } else if (Platform.isWindows) { - return DynamicLibrary.open(locate(windowsLib)); + return _locate(windowsLib) ?? DynamicLibrary.executable(); } else if (Platform.isLinux) { - return DynamicLibrary.open(locate(linuxLib)); + return _locateOrError(linuxLib); } else if (Platform.isAndroid) { return DynamicLibrary.open(linuxLib); } else if (Platform.isFuchsia) { @@ -71,12 +52,25 @@ const windowsLib = 'minifyhtml.dll'; const _minifyhtmlToolDir = '.dart_tool/minifyhtml/'; -String? _packageRootUri(Uri root, String libName) { - do { - final filePath = root.resolve(libName).toFilePath(); - if (FileSystemEntity.isFileSync(filePath)) { - return filePath; - } - } while (root != (root = root.resolve('..'))); +DynamicLibrary? _locate(String libName) { + if (FileSystemEntity.isFileSync(libName)) { + return DynamicLibrary.open(libName); + } + + final toolLib = + Directory.current.uri.resolve("$_minifyhtmlToolDir$libName").toFilePath(); + if (FileSystemEntity.isFileSync(toolLib)) { + return DynamicLibrary.open(toolLib); + } + return null; } + +DynamicLibrary _locateOrError(String libName) { + final value = _locate(libName); + if (value != null) { + return value; + } else { + throw MinifyHtmlLocatorError('MinifyHtml library not found'); + } +}