Autor Zpráva
1Pupik1989
Profil
Zdravím. Snažím se pro zábavu udělat minimalizer javascript kódu. Zůstal jsem ale viset na vyhledání funkcí v řetězci. Respektive mám problém, pokud je ve funkci vnořená další funkce.

var str = "function neco(a,b,c){function neco2(){var c=3;};};function neco3(){var z=3;};var prd=4;";
var reg = /function (\w+)\((.*?)\)\{([^\}]+)\};/g;

//výsledek: ["function neco(a,b,c){function neco2(){var c=3;};", "function neco3(){var z=3;};"] 
//a já chci: ["function neco(a,b,c){function neco2(){var c=3;};};", "function neco3(){var z=3;};};"] 

Vnořenou funkci "neco2" to může klidně vynechat.

Nemá někdo nějaký typ jak na to. Případně pokud existuje jiný princip, tak budu rád, když se podělíte.

Děkuji za pomoc.
DarkKnight
Profil
Potřebuješ udělat vyhledávač, nebo chceš jenom prostě přetransformovat text na řetězec bez háčků apd.?
1Pupik1989
Profil
No ve finále by to měl být zjednodušení proměnných. Prakticky to bude to přetransformování.

Příklad:
//převést z:
function Scitani(prvni_parametr,druhy_parametr){
  return prvni_parametr+druhy_parametr;
};

//na:
function Scitani(a,b){return a+b;};

Pokud to bude lokální funkce, tak i jí chci přejmenovat.

Zatím používám regulární výraz:
/function\s+(\w+)\((.*?)\){(.*?(};)*)};/g
1Pupik1989
Profil
Tak mě napadlo řešení:

/function\s*(\w+)\((.*?)\){(.*?[};]*)};/

Testuji, testuji a zdá se, že funguje. Pokud by měl někdo nápad na lepší řešení, tak sem s ním prosím.
1Pupik1989
Profil
Ta ne, předchozí výraz je taky špatný. Neví někdo pod čím bych to mohl vyhledat? Zkoušel jsem "regex nested function" a nic moc nevylezlo.
_es
Profil
1Pupik1989:
Také veci cez regulárne výrazy asi nevyriešiš. Prečo nepoužiješ už hotové aplikácie na ten účel?
1Pupik1989
Profil
Nepoužil jsem hotovou, protože jsem chtěl vědět jak ty obfuscatory mohou fungovat. Navíc mám knihovnu rozdělenou na několik skupin a jejich metod. No a chtěl jsem docílit co nejmenšího přenosu kódu. Metody načítám přes svou hotovou metodu v knihovně. Samozřejmě momentálně používám YUV Compressor, ale je zdlouhavé otevírat stránku, vložit kód, zkopírovat, vložit a tak třeba několikrát denně.
Jan Tvrdík
Profil
1Pupik1989:
Minifikaci můžeš spouštět i z příkazové řádky, třeba přes node.js.
1Pupik1989
Profil
Jan Tvrdík:
Já právě nechtěl hotové řešení. Moc neholduji knihovnám. Nemělo by smysl mít knihovnu, která bude závislá na 30 dalších.
Jan Tvrdík
Profil
1Pupik1989:
Já právě nechtěl hotové řešení.
Vzhledem ke způsobu, jakým ses snažil tu minifikaci řešit očividně nemáš dostatečný teoretický základ, abys ten problém dokázal uspokojivě řešit. Použití hotové knihovny je tedy adekvátní řešení. Něco málo o minifikaci JS napsal Jakub Vrána.

Nemělo by smysl mít knihovnu, která bude závislá na 30 dalších.
Místo node.js můžeš použít v podstatě libovolný jazyk, který umí zapisovat na disk (PHP, C++, …). Tohle navíc není runtime závislost, takže vadí o poznání méně.
1Pupik1989
Profil
Jan Tvrdík:
Pokud čtu článku, co napsal Jakub Vrána a hlavně textu "Úlohu jsem vyřešil pomocí regulárního výrazu.", si myslím, že k tomu přistupuji správně. Jen nemá asi smysl tímto způsobem vybírat funkce. Zkusím to jinak.
Chamurappi
Profil
Reaguji na 1Pupika1989:
Také jsem přemýšlel, že si napíšu vlastní minifikátor, ale samotný základní cíl (že by měl být děsně chytrý) je až odpudivě složitý :-)
Docela se mi na první pohled zamlouvá Google Closure Compiler, ovšem ten vyžaduje od autora minifikovaného skriptu určitou ne zcela přirozenou sebekázeň, která mým velkým projektům zatím schází, takže jsem neměl příležitost ho vyzkoušet v praxi.

Případně pokud existuje jiný princip, tak budu rád, když se podělíte.
Zkusil bych na to jít z druhé strany. Co všechno se může nacházet ve funkci? Literály řetězců, regulárů, čísla, booleany, null a undefined, klíčová slova, operátory… a pokud rozeznáš tohle všechno, co zůstane? Identifikátory.
1Pupik1989
Profil
Chamurappi:
Jít na to z druhé strany mě nenapadlo, ale určitě to stojí za odzkoušení.

O Google Closure Compiler spoustu lidí tvrdí, že dokáže smrsknout kód až o dvě třetiny. Sám jsem ho ale zatím nezkoušel.

function prvni_funkce(){
  var test = "ahoj";
  function druha(promenna){return promenna;};
  function treti(){
    var text='test';
    var objekt = {
      prvni:3,
      druha:{b:3}
    };
    var dalsi_promenna = "test";
  };
  /*
    neco co ma zmizet
  */
  //function hidden(){}
  function emptys(){};
  function empty2(){ };
};
function pata(prvni,druhy){
  return prvni+druhy;
};
var promenna=2.89;
var promenna2=2;


Momentálně dokážu tento kód zkrátit o 54%. Odtraňuji jen komentáře, prázdné funkce a řádky s přebytečnými mezerami.

Chci docílit i zkrácení proměnných a odstranění nevyužitých proměnných. Proto jsem chtěl vymyslet ten regulární výraz. Postupně bych totiž z vnější funkce až k vnitřní přejmenovával proměnné. Bohužel pokus byl marný.
juriad
Profil
A postupně začínáš řešit dataflow. Pokud chceš odhalit proměnné, které se nikdy nepoužijí, funkce, které se nikdy nezavolají, podmínky, které budou vždy false, tak máš zábavu na mnoho večerů a čtení desítek článků, které na toto téma byly publikovány.
http://closure-compiler.appspot.com/home, tak si ho zkus:
Original Size:     372 bytes (226 bytes gzipped)
Compiled Size:     85 bytes (90 bytes gzipped)
    Saved 77.15% off the original size (60.18% off the gzipped size)
1Pupik1989
Profil
Hlavně musím vymyslet jak docílit co nejméně procházení cyklem. Tu eliminaci nechám až nakonec.
juriad
Profil
function obal() {
  // složitější cyklická závislost
  var nulta, prvni, druha;

  nulta = function() {
    return prvni() || druha();
  }
  
  prvni = function() {
    return druha() || nulta();
  }
  
  druha = function() {
    return nulta() || prvni();
  }
  
  // rekurze
  function posledni() {
    posledni();
  }
}

Prázdné funkce jen tak odstraňovat nemůžeš, pokud nedokážeš, že taková funkce nemůže být zavolaná, nebo nezměníš místo volání (zrušit příkaz, což také není triviální)
function empty() {}
if(empty() || 1 < 2){empty()}
Jan Tvrdík
Profil
1Pupik1989:
Chci docílit i zkrácení proměnných a odstranění nevyužitých proměnných.
Jak už jsem ti tu psal, tohle je mnohem složitější, než si teď možná připouštíš :) Základní minimalizace (jen odstraňování mezer) se dá udělat na úrovni lexémů (výsledek lexikální analýzy) a ve velmi hrubé formě ji provádí právě ten Jakubův JsShrink. Pro pochopení se můžeš taky podívat jak funguje minimalizace PHP od Davida Grudla.

Složitější minimalizaci už ale obvykle na úrovni lexémů udělat nelze a vyžaduje sestavení kompletního abstraktního syntaktického stromu (jsou i alternativní postupy, ale AST je dnes většinou preferovaný). A tím se v podstatě pomalu dostáváš tam, kde třeba UglifyJS začíná :)

Teď jsem si vzpomněl, že zkracování názvu proměnných (v PHP) na úrovni lexémů popsal Jakub Vrána u sebe na blogu. Obávám se ale, že do JS to jen tak přepsat nepůjde.
1Pupik1989
Profil
Přepsat token_get_all do javascriptu asi sranda nebude. Nechám to pár dní uležet, třeba mě napadne úplně jiné řešení.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: