How do I change Closure Compiler compile options not exported to command line? - google-closure-compiler

I found that some options in CompilerOption are not exported to the command line.
For example, alias all strings is available in the Closure Compiler's Java API CompilerOption but I have no idea how set this in the command line.
I know I can create a new java class, like:
Compiler c = new Compiler();
ComppilerOptions opt = new ComppilerOptions();
opt.setAliasAllString(true);
c.compile(.....);
However I have to handle the command line args myself.
Any simple idea?
============================
In order to try the alias all string option, I write a simple command line application based on compiler.jar.
However I found that, the result I got when open the alias all string is not what I expected.
For example:
a["prototype"]["say"]=function(){
var a="something string";
}
Given the above code, the something string will be replaced by a variable like this:
var xx="something string";
....
var a=xx;
....
This is fine, but how about the string "say"? How does the closure compiler know this should be aliased(replace it use variable) or exported(export this method)?
This is the compiled code now:
a.prototype.say=function(){....}
It seems that it export it.
While I want this:
var a="prototype",b="say",c="something string";
xx[a][b]=function(){.....}
In fact, this is the google_map-like compilation.
Is this possible?

Not all options are available from the command line - this includes aliasAllStrings. For some of them you have the following options:
Build a custom version of the compiler
Use the Java API (see example).
Use plovr
Getting the same level of compression and obfuscation as the Maps API requires code written specifically for the compiler. When properly written, you'll see property and namespace collapsing, prototype aliasing and a whole host of others. For an example of the style of code that will optimize that way, take a look at the Closure Library.

Modifying http://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/javascript/jscomp/CompilationLevel.java?r=706 is usually easy enough if you just want to play with something.

Plovr (a Closure build tool) provides an option called experimental-compiler-options, which is documented as follows:
The Closure Compiler contains many options that are only available programmatically in Java. Many of these options are experimental or not finalized, so they may not be a permanent part of the API. Nevertheless, many of them will be useful to you today, so plovr attempts to expose these the experimental-compiler-options option. Under the hood, it uses reflection in Java, so it is fairly hacky, but in practice, it is a convenient way to experiment with Closure Compiler options without writing Java code.

Related

setting CilBody.KeepOldMaxStack or MetadataOptions.Flags

While decompiling .net assembly using de4dot I am getting following message in console:
Error calculating max stack value. If the method's obfuscated, set CilBody.KeepOldMaxStack or MetadataOptions.Flags (KeepOldMaxStack, global option) to ignore this error
How do I set CilBody.KeepOldMaxStack or MetadataOptions.Flags?
Maybe a bit late, but I ran into the same problem today, finding your open question while looking for a solution, and this is how I solved it - I hope it works for you, too:
// Working with an assembly definition
var ass = AssemblyDef.Load("filename.dll");
// Do whatever you want to do with dnLib here
// Create global module writer options
var options = new ModuleWriterOptions(ass.Modules[0]);
options.MetadataOptions.Flags |= MetadataFlags.KeepOldMaxStack;
// Write the new assembly using the global writer options
ass.Write("newfilename.dll", options);
If you want to set the flag only for a selection of methods that produce the problem before writing, just for example:
// Find the type in the first module, then find the method to set the flag for
ass.Modules[0]
.Types.First((type) => type.Name == nameof(TypeToFind))
.FindMethod(nameof(MethodToFind))
.KeepOldMaxStack = true;
CilBody is maybe a bit confusing, if you're not too deep into the internal .NET assembly structures: It simply means the body object of the method that produces the problem, when writing the modified assembly. Obfuscators often try to confuse disassemblers by producing invalid structures, what may cause a problem when calculating the maxstack value before writing the assembly with dnLib. By keeping the original maxstack value, you can step over those invalid method structures.
In the context of de4dot it seems to be a bug, or the application is simply not designed to solve invalid method structures of obfuscated assemblies - in this case there's no solution for you, if the de4net developer won't fix/implement it, and you don't want to write a patch using the source code from GitHub.

How to make Flow understand code written for Node.js?

I'm just getting started with Flow, trying to introduce it into an existing Node codebase.
Here are two lines Flow complains about:
import Module from 'module';
const nodeVersion = Number(process.versions.node.split('.')[0]);
The warnings about these lines are, respectively:
module. Required module not found
call of method `split`. Method cannot be called on possibly null value
So it seems like Flow isn't aware of some things that are standard in a Node environment (e.g. process.versions.node is guaranteed to be a string, and there is definitely a Node builtin called module).
But then again, Flow's configuration docs suggest it's Node-aware by default. And I have plenty of other stuff like import fs from 'fs'; which does not cause any warning. So what am I doing wrong?
Module fs works as expected because Flow comes with built-in definitions for it, see declare module "fs" here: https://github.com/facebook/flow/blob/master/lib/node.js#L624
Regarding process.versions.node, you can see in the same file that the versions key is typed as a map of nullable strings, with no mention of the specific node property: versions : { [key: string] : ?string };. So you'll need to either make a PR to improve this definition, or adjust your code for the possibility of that value being null.
I guess the answer about module "module" is obvious now – there are no built-in definitions for that module in Flow in lib/node.js. You could write your own definitions, and optionally send a PR with them to the Flow team. You can also try searching github for these, someone might have done the work already.
That lib directory is very useful by the way, it has Flow definitions for DOM and other stuff as well.

Injection using Spicelib command group syntax

I'm using Parsley 3.0 with the Flex extensions, but was wanting to use the spicelib syntax for executing a command group:
Commands.asSequence()
.create(LoadCachedCredentialsCommand)
.create(LoginCommand)
.lastResult(appInit_resultHandler)
.error(appInit_errorHandler)
.execute();
When doing it like this, I've noticed that injection with metadata in the commands do not work. Is this expected behavior? I assumed all the normal functionality with injection when defining the commands in the context would also work in this situation. But I wanted to confirm this to make sure I wasn't simply doing something wrong.
This is expected, as Spicelib itself does not know about Parsley. If you want your sequence to be managed by Parsley, you need to add it manually to the context:
var sequence:Command = Commands.asSequence()
.create(LoadCachedCredentialsCommand)
.create(LoginCommand)
.lastResult(appInit_resultHandler)
.error(appInit_errorHandler)
.execute();
var context:Context = ...;
ManagedCommands.wrap(sequence)
.execute(context);
See also here in the Parsley documentation.

How can I tell the Closure Compiler not to rename an inner function using SIMPLE_OPTIMIZATIONS?

How can I tell the Closure Compiler not to rename an inner function? E.g., given this code:
function aMeaninglessName() {
function someMeaningfulName() {
}
return someMeaningfulName;
}
...I'm fine with Closure renaming the outer function (I actively want it to, to save space), but I want the function name someMeaningfulName left alone (so that the name shown in call stacks for it is "someMeaningfulName", not "a" or whatever). This despite the fact that the code calling it will be doing so via the reference returned by the factory function, not by the name in the code. E.g., this is purely for debugging support.
Note that I want the function to have that actual name, not be anonymous and assigned to some property using that name, so for instance this is not a duplicate of this other question.
This somewhat obscure use case doesn't seem to be covered by either the externs or exports functionality. (I was kind of hoping there'd be some annotation I could throw at it.) But I'm no Closure Compiler guru, I'm hoping some of you are. Naturally, if there's just no way to do that, that's an acceptable answer.
(The use case is a library that creates functions in response to calls into it. I want to provide a version of the library that's been pre-compressed by Closure with SIMPLE_OPTIMIZATIONS, but if someone is using that copy of the library with their own uncompressed code and single-stepping into the function in a debugger [or other similar operations], I want them to see the meaningful name. I could get around it with eval, or manually edit the compressed result [in fact, the context is sufficiently unique I could throw a sed script at it], but that's awkward and frankly takes us into "not worth bothering" territory, hence looking for a simple, low-maintenance way.)
There is no simple way to do this. You would have to create a custom subclass of the CodingConvention class to indicate that your methods are "local" externs (support for this was added to handle the Prototype library). It is possible that InlineVariables, InlineFunctions, or RemoveUsedVariables will still try to remove the name and would also need to be fixed up.
Another approach is to use the source maps to remap the stack traces to the original source.
read the following section
https://developers.google.com/closure/compiler/docs/api-tutorial3#export
Two options basically, use object['functionName'] = obj.functionName or the better way
use exportSymbol and exportProperty both on the goog object, here is the docs link for that
http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.html
-- edit
ah, i see now, my first answer is not so great for you. The compiler has some interesting flags, the one which might interest you is DEBUG, which you can pass variables into the compiler which will allow you to drop some debugging annotations in via logging or just a string which does nothing since you are using simple mode.
so if you are using closure you can debug against a development version which is just a page built with dependiencies resolved. we also the drop the following in our code
if(DEBUG){
logger.info('pack.age.info.prototype.func');
}

Flex Compile Time Constants - Timestamp

I'm trying to use Flex Compile Time Constants to include the date and time the SWF was built (source control revision/timestamp such as SVN:Keywords is not sufficient for our needs, we need to know the actual build time, not the commit time).
I've tried using actionscript (like the documentation suggests you should be able to):
-define+=COMPILE::Timestamp,"new Date()"
But this gives "The initializer for a configuration value must be a compile time constant"
I've tried getting it to drop to shell and use the date command (using various single and double quote configurations), for example:
-define+=COMPILE::Timestamp,`date +%Y%m%d%H%M%S`
I can only get it to work with simple strings and simple constant expressions (eg, I can do 4-2 and it'll be 2 at runtime. But I can't get it to do anything whose value wouldn't be explicitly known at the time I declare the define.
Has anyone had any luck with something like this?
I had the same problem and ended up using this blog post as a starting point. Worked really well for me. Just had to update a few bits of the class to flex 4. Pulled the date right out of the complied swf.
The key to your problem is most likely in the following statement by Adobe referring to Compile Time Constants:
The constant can be a Boolean, String, or Number, or an expression that can be evaluated in ActionScript at compile time.
I would assume that the Timestamp is not available at compile time.
However, you may try using a string instead (something like this)
public function GetUnixTime():String{
var myDate:Date = new Date();
var unixTime:Number = Math.round(myDate.getTime()/1000);
return unixTime.toString();
}
Another thought is that you could get the information from the compiled file.
Hope this helps.
After extensive research, I've concluded that this simply isn't doable.
If you don't use FlexBuilder to do your builds you can do it quite easily.
I do something like this with FlexMojos in Maven.
In the relevant config section:
<definesDeclaration>
<property><name>BUILD::buildVersion</name><value>"${project.version}"</value></property>
<property><name>BUILD::buildRevision</name><value>"${buildNumber}"</value></property>
<property><name>BUILD::buildTimestamp</name><value>"${timestamp}"</value></property>
</definesDeclaration>
FlexBuilder pretty much sucks as a build environment for reasons like the one you mention

Resources