You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@royale.apache.org by jo...@apache.org on 2021/01/20 21:15:49 UTC

[royale-compiler] branch develop updated: playerglobal-source-gen: initial commit

This is an automated email from the ASF dual-hosted git repository.

joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git


The following commit(s) were added to refs/heads/develop by this push:
     new 97c4e5b  playerglobal-source-gen: initial commit
97c4e5b is described below

commit 97c4e5b1082c2364ac04cb4db922067fe71e8883
Author: Josh Tynjala <jo...@apache.org>
AuthorDate: Wed Jan 20 12:45:37 2021 -0800

    playerglobal-source-gen: initial commit
---
 playerglobal-source-gen/pom.xml                    |   87 ++
 .../royale/playerglobal/PlayerglobalSourceGen.java | 1048 ++++++++++++++++++++
 2 files changed, 1135 insertions(+)

diff --git a/playerglobal-source-gen/pom.xml b/playerglobal-source-gen/pom.xml
new file mode 100644
index 0000000..0dc5648
--- /dev/null
+++ b/playerglobal-source-gen/pom.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+--><project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.royale</groupId>
+  <artifactId>playerglobal-source-gen</artifactId>
+  <name>playerglobal-source-gen</name>
+  <version>1.0.0</version>
+  
+  <build>
+    <finalName>${project.artifactId}</finalName>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.8.1</version>
+        <configuration>
+          <source>1.8</source>
+          <target>1.8</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>3.2.0</version>
+        <configuration>
+          <archive>
+            <manifest>
+              <mainClass>org.apache.royale.playerglobal.PlayerglobalSourceGen</mainClass>
+              <addClasspath>true</addClasspath>
+            </manifest>
+          </archive>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}</outputDirectory>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.dom4j</groupId>
+      <artifactId>dom4j</artifactId>
+      <version>2.1.3</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/playerglobal-source-gen/src/main/java/org/apache/royale/playerglobal/PlayerglobalSourceGen.java b/playerglobal-source-gen/src/main/java/org/apache/royale/playerglobal/PlayerglobalSourceGen.java
new file mode 100644
index 0000000..569fd06
--- /dev/null
+++ b/playerglobal-source-gen/src/main/java/org/apache/royale/playerglobal/PlayerglobalSourceGen.java
@@ -0,0 +1,1048 @@
+/*
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+package org.apache.royale.playerglobal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.dom4j.Document;
+import org.dom4j.Element;
+import org.dom4j.io.SAXReader;
+
+/**
+ * Generates .as source files to build playerglobal.swc and airglobal.swc from
+ * the ASDoc DITA XML files.
+ * 
+ * Usage:
+ * 
+ * java -jar playerglobal-source-gen.jar flex-sdk/frameworks/projects/playerglobal/bundles/en_US/docs/
+ * java -jar playerglobal-source-gen.jar flex-sdk/frameworks/projects/playerglobal/bundles/en_US/docs/ target/generated-sources/
+ */
+class PlayerglobalSourceGen {
+	public static void main(String[] args) {
+		if (args.length == 0) {
+			System.err.println("Must specify docs folder path");
+			System.exit(1);
+		}
+		if (args.length > 2) {
+			System.err.println("Too many arguments. Required docs folder path. Optional target folder path.");
+			System.exit(1);
+		}
+		File sourceFolder = new File(args[0]);
+		File targetFolder = (args.length == 2) ? new File(args[1])
+				: new File(System.getProperty("user.dir"), "target/generated-sources/");
+		PlayerglobalSourceGen sourceGen = new PlayerglobalSourceGen(sourceFolder, targetFolder);
+		try {
+			sourceGen.generateSources();
+		} catch (Exception e) {
+			System.err.println(e.getMessage());
+			System.exit(1);
+		}
+	}
+
+	private static final List<String> VECTOR_SUFFIXES = Arrays.asList("$double", "$int", "$uint", "$object");
+
+	private File sourceFolder;
+	private File targetFolder;
+	private File currentFile;
+
+	public PlayerglobalSourceGen(File sourceFolder, File targetFolder) {
+		this.sourceFolder = sourceFolder;
+		this.targetFolder = targetFolder;
+	}
+
+	public void generateSources() throws Exception {
+		preclean();
+
+		for (File sourceFile : sourceFolder.listFiles()) {
+			if (sourceFile.isDirectory()) {
+				continue;
+			}
+			String sourceFileName = sourceFile.getName();
+			if (!sourceFileName.endsWith(".xml")) {
+				continue;
+			}
+			if (sourceFileName.endsWith(".dita.xml")) {
+				continue;
+			}
+			parseFile(sourceFile);
+		}
+	}
+
+	private void preclean() throws Exception {
+		File playerglobalFolder = new File(targetFolder, "playerglobal");
+		FileUtils.deleteDirectory(playerglobalFolder);
+		File airglobalFolder = new File(targetFolder, "airglobal");
+		FileUtils.deleteDirectory(airglobalFolder);
+	}
+
+	private void writeFileForDefinition(String fullyQualifiedName, boolean airOnly, String contents)
+			throws IOException {
+		StringBuilder fileNameBuilder = new StringBuilder();
+		if (airOnly) {
+			fileNameBuilder.append("airglobal");
+		} else {
+			fileNameBuilder.append("playerglobal");
+		}
+		String[] parts = fullyQualifiedName.split("\\.");
+		for (String part : parts) {
+			fileNameBuilder.append("/");
+			fileNameBuilder.append(part);
+		}
+		fileNameBuilder.append(".as");
+		File targetFile = new File(this.targetFolder, fileNameBuilder.toString());
+		FileUtils.writeStringToFile(targetFile, contents);
+	}
+
+	private boolean isAIROnly(Element prologElement) {
+		if (prologElement == null) {
+			return false;
+		}
+		Element asMetadataElement = prologElement.element("asMetadata");
+		if (asMetadataElement == null) {
+			return false;
+		}
+		Element apiVersionElement = asMetadataElement.element("apiVersion");
+		if (apiVersionElement == null) {
+			return false;
+		}
+		List<Element> apiPlatformElements = apiVersionElement.elements("apiPlatform");
+		if (apiPlatformElements == null || apiPlatformElements.size() == 0) {
+			return false;
+		}
+		for (Element apiPlatformElement : apiPlatformElements) {
+			if (!"AIR".equals(apiPlatformElement.attributeValue("name"))) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	private void parseFile(File ditaFile) throws Exception {
+		currentFile = ditaFile;
+		String contents = null;
+		try {
+			contents = FileUtils.readFileToString(ditaFile, Charset.forName("utf8"));
+		} catch (Exception e) {
+			System.err.println("Failed to read XML file: " + ditaFile.getAbsolutePath());
+			return;
+		}
+
+		SAXReader xmlReader = new SAXReader();
+		Document xmlDoc = xmlReader.read(new StringReader(contents));
+
+		Element apiPackageElement = xmlDoc.getRootElement();
+		if (!"apiPackage".equals(apiPackageElement.getName())) {
+			throw new Exception("No apiPackage root element: " + ditaFile.getAbsolutePath());
+		}
+
+		parsePackage(apiPackageElement);
+		currentFile = null;
+	}
+
+	private void parsePackage(Element apiPackageElement) throws Exception {
+		for (Element apiOperationElement : apiPackageElement.elements("apiOperation")) {
+			parsePackageFunction(apiOperationElement);
+		}
+		for (Element apiValueElement : apiPackageElement.elements("apiValue")) {
+			parsePackageVariable(apiValueElement);
+		}
+		for (Element apiClassifierElement : apiPackageElement.elements("apiClassifier")) {
+			Element apiClassifierDetailElement = apiClassifierElement.element("apiClassifierDetail");
+			if (apiClassifierDetailElement == null) {
+				String fullyQualifiedName = apiClassifierElement.attributeValue("id");
+				throw new Exception("Not found: " + fullyQualifiedName);
+			}
+			Element apiClassifierDefElement = apiClassifierDetailElement.element("apiClassifierDef");
+			if (apiClassifierDefElement == null) {
+				String fullyQualifiedName = apiClassifierElement.attributeValue("id");
+				throw new Exception("Not found: " + fullyQualifiedName);
+			}
+			Element apiInterfaceElement = apiClassifierDefElement.element("apiInterface");
+			if (apiInterfaceElement != null) {
+				parseInterface(apiClassifierElement);
+				continue;
+			}
+			parseClass(apiClassifierElement);
+		}
+	}
+
+	private void parseClass(Element apiClassifierElement) throws Exception {
+		String fullyQualifiedName = apiClassifierElement.attributeValue("id");
+		if (fullyQualifiedName.startsWith("globalClassifier:")) {
+			fullyQualifiedName = fullyQualifiedName.substring(17);
+		}
+		if (fullyQualifiedName.equals("Vector")) {
+			//special case in the compiler that doesn't get exposed in docs
+			fullyQualifiedName = "__AS3__.vec:Vector";
+			StringBuilder vectorBuilder = new StringBuilder();
+			vectorBuilder.append("// generated from: ");
+			vectorBuilder.append(currentFile.getName());
+			vectorBuilder.append("\n");
+			vectorBuilder.append("package __AS3__.vec {\n");
+			vectorBuilder.append("\tpublic final dynamic class Vector {\n");
+			vectorBuilder.append("\tpublic native function Vector();\n");
+			vectorBuilder.append("\t}\n");
+			vectorBuilder.append("}\n");
+			writeFileForDefinition("__AS3__.vec.Vector", false, vectorBuilder.toString());
+			for (String suffix : VECTOR_SUFFIXES) {
+				parseClassWithFullyQualifiedName(apiClassifierElement, fullyQualifiedName + suffix);
+			}
+			return;
+		}
+		parseClassWithFullyQualifiedName(apiClassifierElement, fullyQualifiedName);
+	}
+
+	private void parseClassWithFullyQualifiedName(Element apiClassifierElement, String fullyQualifiedName)
+			throws Exception {
+
+		String[] parts = fullyQualifiedName.split(":");
+		String packageName = "";
+		String className = fullyQualifiedName;
+		if (parts.length > 1) {
+			packageName = parts[0];
+			className = parts[1];
+			fullyQualifiedName = packageName + "." + className;
+		}
+
+		boolean isAIROnly = isAIROnly(apiClassifierElement.element("prolog"));
+		boolean isVector = className.startsWith("Vector$");
+
+		Set<String> importFullyQualifiedNames = new HashSet<>();
+		collectImports(apiClassifierElement, packageName, importFullyQualifiedNames);
+
+		String baseClassFullyQualifiedName = "";
+		List<String> interfaceFullyQualifiedNames = new ArrayList<>();
+		String access = null;
+		boolean isFinal = false;
+		boolean isDynamic = false;
+
+		Element apiClassifierDetailElement = apiClassifierElement.element("apiClassifierDetail");
+		if (apiClassifierDetailElement == null) {
+			throw new Exception("apiClassifierDetail not found for: " + className);
+		}
+		Element apiClassifierDefElement = apiClassifierDetailElement.element("apiClassifierDef");
+		if (apiClassifierDefElement == null) {
+			throw new Exception("apiClassifierDef not found for: " + className);
+		}
+
+		Element apiBaseClassifierElement = apiClassifierDefElement.element("apiBaseClassifier");
+		if (apiBaseClassifierElement != null) {
+			baseClassFullyQualifiedName = apiBaseClassifierElement.getTextTrim();
+			baseClassFullyQualifiedName = baseClassFullyQualifiedName.replace(":", ".");
+		}
+
+		List<Element> apiBaseInterfaceElements = apiClassifierDefElement.elements("apiBaseInterface");
+		for (Element apiBaseInterfaceElement : apiBaseInterfaceElements) {
+			String interfaceFullyQualifiedName = apiBaseInterfaceElement.getTextTrim();
+			interfaceFullyQualifiedName = interfaceFullyQualifiedName.replace(":", ".");
+			interfaceFullyQualifiedNames.add(interfaceFullyQualifiedName);
+		}
+
+		Element apiAccessElement = apiClassifierDefElement.element("apiAccess");
+		if (apiAccessElement != null) {
+			access = apiAccessElement.attributeValue("value");
+		}
+		if (isVector) {
+			access = "internal";
+		}
+
+		Element apiFinalElement = apiClassifierDefElement.element("apiFinal");
+		if (apiFinalElement != null) {
+			isFinal = true;
+		}
+
+		Element apiDynamicElement = apiClassifierDefElement.element("apiDynamic");
+		if (apiDynamicElement != null) {
+			isDynamic = true;
+		}
+
+		Element apiConstructorElement = apiClassifierElement.element("apiConstructor");
+		List<Element> apiOperationElements = apiClassifierElement.elements("apiOperation");
+		List<Element> apiValueElements = apiClassifierElement.elements("apiValue");
+
+		StringBuilder classBuilder = new StringBuilder();
+		classBuilder.append("// generated from: ");
+		classBuilder.append(currentFile.getName());
+		classBuilder.append("\n");
+		classBuilder.append("package");
+		if (packageName.length() > 0) {
+			classBuilder.append(" ");
+			classBuilder.append(packageName);
+		}
+		classBuilder.append(" ");
+		classBuilder.append("{");
+		classBuilder.append("\n");
+		writeImports(importFullyQualifiedNames, classBuilder);
+		classBuilder.append("\t");
+		if (access != null && access.length() > 0) {
+			classBuilder.append(access);
+			classBuilder.append(" ");
+		}
+		if (isFinal) {
+			classBuilder.append("final ");
+		}
+		if (isDynamic) {
+			classBuilder.append("dynamic ");
+		}
+		classBuilder.append("class ");
+		classBuilder.append(className);
+		if (baseClassFullyQualifiedName != null && baseClassFullyQualifiedName.length() > 0
+				&& !"Object".equals(baseClassFullyQualifiedName)) {
+			classBuilder.append(" extends ");
+			classBuilder.append(baseClassFullyQualifiedName);
+		}
+		for (int i = 0; i < interfaceFullyQualifiedNames.size(); i++) {
+			String interfaceFullyQualifiedName = interfaceFullyQualifiedNames.get(i);
+			if (i == 0) {
+				classBuilder.append(" implements ");
+			} else {
+				classBuilder.append(", ");
+			}
+			classBuilder.append(interfaceFullyQualifiedName);
+		}
+		classBuilder.append(" ");
+		classBuilder.append("{");
+		classBuilder.append("\n");
+		if (apiConstructorElement != null) {
+			parseConstructor(apiConstructorElement, className, classBuilder);
+		}
+		for (Element apiOperationElement : apiOperationElements) {
+			parseFunction(apiOperationElement, className, false, classBuilder);
+		}
+		for (Element apiValueElement : apiValueElements) {
+			parseVariable(apiValueElement, false, classBuilder);
+		}
+		classBuilder.append("\t");
+		classBuilder.append("}");
+		classBuilder.append("\n");
+		classBuilder.append("}");
+		classBuilder.append("\n");
+
+		writeFileForDefinition(fullyQualifiedName, isAIROnly, classBuilder.toString());
+	}
+
+	private void parseInterface(Element apiClassifierElement) throws Exception {
+		String fullyQualifiedName = apiClassifierElement.attributeValue("id");
+		if (fullyQualifiedName.startsWith("globalClassifier:")) {
+			fullyQualifiedName = fullyQualifiedName.substring(17);
+		}
+
+		String[] parts = fullyQualifiedName.split(":");
+		String packageName = "";
+		String interfaceName = fullyQualifiedName;
+		if (parts.length > 1) {
+			packageName = parts[0];
+			interfaceName = parts[1];
+			fullyQualifiedName = packageName + "." + interfaceName;
+		}
+
+		boolean isAIROnly = isAIROnly(apiClassifierElement.element("prolog"));
+
+		Set<String> importFullyQualifiedNames = new HashSet<>();
+		collectImports(apiClassifierElement, packageName, importFullyQualifiedNames);
+
+		List<String> interfaceFullyQualifiedNames = new ArrayList<>();
+		String access = null;
+
+		Element apiClassifierDetailElement = apiClassifierElement.element("apiClassifierDetail");
+		if (apiClassifierDetailElement == null) {
+			throw new Exception("apiClassifierDetail not found for: " + interfaceName);
+		}
+		Element apiClassifierDefElement = apiClassifierDetailElement.element("apiClassifierDef");
+		if (apiClassifierDefElement == null) {
+			throw new Exception("apiClassifierDef not found for: " + interfaceName);
+		}
+
+		List<Element> apiBaseInterfaceElements = apiClassifierDefElement.elements("apiBaseInterface");
+		for (Element apiBaseInterfaceElement : apiBaseInterfaceElements) {
+			String baseInterfaceFullyQualifiedName = apiBaseInterfaceElement.getTextTrim();
+			baseInterfaceFullyQualifiedName = baseInterfaceFullyQualifiedName.replace(":", ".");
+			interfaceFullyQualifiedNames.add(baseInterfaceFullyQualifiedName);
+		}
+
+		Element apiAccessElement = apiClassifierDefElement.element("apiAccess");
+		if (apiAccessElement != null) {
+			access = apiAccessElement.attributeValue("value");
+		}
+
+		List<Element> apiOperationElements = apiClassifierElement.elements("apiOperation");
+		List<Element> apiValueElements = apiClassifierElement.elements("apiValue");
+
+		StringBuilder interfaceBuilder = new StringBuilder();
+		interfaceBuilder.append("// generated from: ");
+		interfaceBuilder.append(currentFile.getName());
+		interfaceBuilder.append("\n");
+		interfaceBuilder.append("package");
+		if (packageName.length() > 0) {
+			interfaceBuilder.append(" ");
+			interfaceBuilder.append(packageName);
+		}
+		interfaceBuilder.append(" ");
+		interfaceBuilder.append("{");
+		interfaceBuilder.append("\n");
+		writeImports(importFullyQualifiedNames, interfaceBuilder);
+		interfaceBuilder.append("\t");
+		if (access != null && access.length() > 0) {
+			interfaceBuilder.append(access);
+			interfaceBuilder.append(" ");
+		}
+		interfaceBuilder.append("interface ");
+		interfaceBuilder.append(interfaceName);
+		for (int i = 0; i < interfaceFullyQualifiedNames.size(); i++) {
+			String interfaceFullyQualifiedName = interfaceFullyQualifiedNames.get(i);
+			if (i == 0) {
+				interfaceBuilder.append(" extends ");
+			} else {
+				interfaceBuilder.append(", ");
+			}
+			interfaceBuilder.append(interfaceFullyQualifiedName);
+		}
+		interfaceBuilder.append(" ");
+		interfaceBuilder.append("{");
+		interfaceBuilder.append("\n");
+		for (Element apiOperationElement : apiOperationElements) {
+			parseFunction(apiOperationElement, null, true, interfaceBuilder);
+		}
+		for (Element apiValueElement : apiValueElements) {
+			parseVariable(apiValueElement, true, interfaceBuilder);
+		}
+		interfaceBuilder.append("\t");
+		interfaceBuilder.append("}");
+		interfaceBuilder.append("\n");
+		interfaceBuilder.append("}");
+		interfaceBuilder.append("\n");
+
+		writeFileForDefinition(fullyQualifiedName, isAIROnly, interfaceBuilder.toString());
+	}
+
+	private void parsePackageFunction(Element apiOperationElement) throws Exception {
+		String fullyQualifiedName = apiOperationElement.attributeValue("id");
+		if (fullyQualifiedName.startsWith("globalOperation:")) {
+			fullyQualifiedName = fullyQualifiedName.substring(16);
+		}
+		if (fullyQualifiedName.equals("Vector")) {
+			//special case in the compiler that doesn't get exposed in docs
+			return;
+		}
+
+		String[] parts = fullyQualifiedName.split(":");
+		String packageName = "";
+		if (parts.length > 1) {
+			packageName = parts[0];
+			fullyQualifiedName = packageName + "." + parts[1];
+		}
+
+		Set<String> importFullyQualifiedNames = new HashSet<>();
+		collectImports(apiOperationElement, packageName, importFullyQualifiedNames);
+
+		boolean isAIROnly = isAIROnly(apiOperationElement.element("prolog"));
+
+		StringBuilder functionBuilder = new StringBuilder();
+		functionBuilder.append("// generated from: ");
+		functionBuilder.append(currentFile.getName());
+		functionBuilder.append("\n");
+		functionBuilder.append("package");
+		if (packageName != null && packageName.length() > 0) {
+			functionBuilder.append(" ");
+			functionBuilder.append(packageName);
+		}
+		functionBuilder.append(" ");
+		functionBuilder.append("{");
+		functionBuilder.append("\n");
+		writeImports(importFullyQualifiedNames, functionBuilder);
+		parseFunction(apiOperationElement, null, false, functionBuilder);
+		functionBuilder.append("}");
+		functionBuilder.append("\n");
+
+		writeFileForDefinition(fullyQualifiedName, isAIROnly, functionBuilder.toString());
+	}
+
+	private void parsePackageVariable(Element apiValueElement) throws Exception {
+		String fullyQualifiedName = apiValueElement.attributeValue("id");
+		if (fullyQualifiedName.startsWith("globalValue:")) {
+			fullyQualifiedName = fullyQualifiedName.substring(12);
+		}
+
+		String[] parts = fullyQualifiedName.split(":");
+		String packageName = "";
+		String variableName = fullyQualifiedName;
+		if (parts.length > 1) {
+			packageName = parts[0];
+			variableName = parts[1];
+			fullyQualifiedName = packageName + "." + variableName;
+		}
+
+		if (variableName.startsWith("-")) {
+			//nothing to do here
+			//it's just a negative value getting documented (like -Infinity)
+			return;
+		}
+
+		Set<String> importFullyQualifiedNames = new HashSet<>();
+		collectImports(apiValueElement, packageName, importFullyQualifiedNames);
+
+		boolean isAIROnly = isAIROnly(apiValueElement.element("prolog"));
+
+		StringBuilder variableBuilder = new StringBuilder();
+		variableBuilder.append("// generated from: ");
+		variableBuilder.append(currentFile.getName());
+		variableBuilder.append("\n");
+		variableBuilder.append("package");
+		if (packageName != null && packageName.length() > 0) {
+			variableBuilder.append(" ");
+			variableBuilder.append(packageName);
+		}
+		variableBuilder.append(" ");
+		variableBuilder.append("{");
+		variableBuilder.append("\n");
+		writeImports(importFullyQualifiedNames, variableBuilder);
+		parseVariable(apiValueElement, false, variableBuilder);
+		variableBuilder.append("}");
+		variableBuilder.append("\n");
+
+		writeFileForDefinition(fullyQualifiedName, isAIROnly, variableBuilder.toString());
+	}
+
+	private void parseVariable(Element apiValueElement, boolean forInterface, StringBuilder variableBuilder)
+			throws Exception {
+		String variableName = apiValueElement.element("apiName").getTextTrim();
+
+		boolean isGetter = false;
+		boolean isSetter = false;
+		boolean isConst = true;
+		boolean isStatic = false;
+		boolean isOverride = false;
+		String variableType = "*";
+		String access = null;
+
+		Element apiValueDetailElement = apiValueElement.element("apiValueDetail");
+		if (apiValueDetailElement == null) {
+			throw new Exception("apiValueDetail not found for: " + variableName);
+		}
+		Element apiValueDefElement = apiValueDetailElement.element("apiValueDef");
+		if (apiValueDefElement == null) {
+			throw new Exception("apiValueDef not found for: " + variableName);
+		}
+
+		Element apiValueClassifierElement = apiValueDefElement.element("apiValueClassifier");
+		if (apiValueClassifierElement != null) {
+			variableType = apiValueClassifierElement.getTextTrim();
+			variableType = variableType.replace(":", ".");
+		}
+
+		Element apiAccessElement = apiValueDefElement.element("apiAccess");
+		if (!forInterface && apiAccessElement != null) {
+			access = apiAccessElement.attributeValue("value");
+		}
+
+		Element apiStaticElement = apiValueDefElement.element("apiStatic");
+		if (!forInterface && apiStaticElement != null) {
+			isStatic = true;
+		}
+
+		Element apiDynamicElement = apiValueDefElement.element("apiDynamic");
+		if (apiDynamicElement != null) {
+			isConst = false;
+		}
+
+		Element apiValueAccessElement = apiValueDefElement.element("apiValueAccess");
+		if (apiValueAccessElement != null) {
+			String readwrite = apiValueAccessElement.attributeValue("value");
+			isGetter = "readwrite".equals(readwrite) || "read".equals(readwrite);
+			isSetter = "readwrite".equals(readwrite) || "write".equals(readwrite);
+		}
+
+		Element apiIsOverrideElement = apiValueDefElement.element("apiIsOverride");
+		if (apiIsOverrideElement != null) {
+			isOverride = true;
+		}
+
+		if (!forInterface && isGetter && isSetter && !isOverride
+				&& apiValueElement.attributeValue("id").endsWith(":set")) {
+			//skip the getter because it is already defined on the base class
+			//example: flash.text.engine.TextElement.text
+			isGetter = false;
+		}
+
+		Element apiDataElement = apiValueDefElement.element("apiData");
+
+		if (isGetter) {
+			variableBuilder.append("\t");
+			if (access != null && access.length() > 0) {
+				variableBuilder.append(access);
+				variableBuilder.append(" ");
+			}
+			if (isStatic) {
+				variableBuilder.append("static ");
+			}
+			if (!forInterface) {
+				variableBuilder.append("native ");
+			}
+			if (isOverride) {
+				variableBuilder.append("override ");
+			}
+			variableBuilder.append("function ");
+			variableBuilder.append("get ");
+			variableBuilder.append(variableName);
+			variableBuilder.append("(");
+			variableBuilder.append(")");
+			variableBuilder.append(":");
+			variableBuilder.append(variableType);
+			variableBuilder.append(";");
+			variableBuilder.append("\n");
+		}
+
+		if (isSetter) {
+			variableBuilder.append("\t");
+			if (access != null && access.length() > 0) {
+				variableBuilder.append(access);
+				variableBuilder.append(" ");
+			}
+			if (isStatic) {
+				variableBuilder.append("static ");
+			}
+			if (!forInterface) {
+				variableBuilder.append("native ");
+			}
+			if (isOverride) {
+				variableBuilder.append("override ");
+			}
+			variableBuilder.append("function ");
+			variableBuilder.append("set ");
+			variableBuilder.append(variableName);
+			variableBuilder.append("(");
+			variableBuilder.append("value");
+			variableBuilder.append(":");
+			variableBuilder.append(variableType);
+			variableBuilder.append(")");
+			variableBuilder.append(":");
+			variableBuilder.append("void");
+			variableBuilder.append(";");
+			variableBuilder.append("\n");
+		}
+
+		if (!isGetter && !isSetter) {
+			variableBuilder.append("\t");
+			if (access != null && access.length() > 0) {
+				variableBuilder.append(access);
+				variableBuilder.append(" ");
+			}
+			if (isStatic) {
+				variableBuilder.append("static ");
+			}
+			if (isConst) {
+				variableBuilder.append("const ");
+			} else {
+				variableBuilder.append("var ");
+			}
+			variableBuilder.append(variableName);
+			variableBuilder.append(":");
+			variableBuilder.append(variableType);
+			if (apiDataElement != null) {
+				writeVariableOrParameterValue(apiDataElement, variableType, variableBuilder);
+			}
+			variableBuilder.append(";");
+			variableBuilder.append("\n");
+		}
+	}
+
+	private void parseFunction(Element apiOperationElement, String contextClassName, boolean forInterface,
+			StringBuilder functionBuilder) throws Exception {
+		String functionName = apiOperationElement.element("apiName").getTextTrim();
+
+		boolean isStatic = false;
+		boolean isOverride = false;
+		String returnType = "*";
+		String access = null;
+
+		Element apiOperationDetailElement = apiOperationElement.element("apiOperationDetail");
+		if (apiOperationDetailElement == null) {
+			throw new Exception("apiOperationDetail not found for: " + functionName);
+		}
+		Element apiOperationDefElement = apiOperationDetailElement.element("apiOperationDef");
+		if (apiOperationDefElement == null) {
+			throw new Exception("apiOperationDef not found for: " + functionName);
+		}
+
+		Element apiIsOverrideElement = apiOperationDefElement.element("apiIsOverride");
+		if (apiIsOverrideElement != null) {
+			isOverride = true;
+		}
+
+		Element apiReturnElement = apiOperationDefElement.element("apiReturn");
+		if (apiReturnElement != null) {
+			Element apiTypeElement = apiReturnElement.element("apiType");
+			if (apiTypeElement != null) {
+				returnType = parseReturnOrParamType(apiTypeElement, contextClassName);
+			}
+			Element apiOperationClassifierElement = apiReturnElement.element("apiOperationClassifier");
+			if (apiOperationClassifierElement != null) {
+				returnType = apiOperationClassifierElement.getTextTrim();
+				returnType = returnType.replace(":", ".");
+			}
+		}
+
+		Element apiAccessElement = apiOperationDefElement.element("apiAccess");
+		if (!forInterface && apiAccessElement != null) {
+			access = apiAccessElement.attributeValue("value");
+		}
+
+		Element apiStaticElement = apiOperationDefElement.element("apiStatic");
+		if (!forInterface && apiStaticElement != null) {
+			isStatic = true;
+		}
+
+		List<Element> apiParamElements = apiOperationDefElement.elements("apiParam");
+
+		if ("public".equals(access) && ("toString".equals(functionName) || "toLocaleString".equals(functionName))
+				|| "valueOf".equals(functionName) || "hasOwnProperty".equals(functionName)
+				|| "propertyIsEnumerable".equals(functionName)) {
+			return;
+		}
+
+		functionBuilder.append("\t");
+		if (access != null && access.length() > 0) {
+			functionBuilder.append(access);
+			functionBuilder.append(" ");
+		}
+		if (isStatic) {
+			functionBuilder.append("static ");
+		}
+		if (!forInterface) {
+			functionBuilder.append("native ");
+		}
+		if (isOverride) {
+			functionBuilder.append("override ");
+		}
+		functionBuilder.append("function ");
+		functionBuilder.append(functionName);
+		functionBuilder.append("(");
+		parseParameters(apiParamElements, contextClassName, functionBuilder);
+		functionBuilder.append(")");
+		functionBuilder.append(":");
+		functionBuilder.append(returnType);
+		functionBuilder.append(";");
+		functionBuilder.append("\n");
+	}
+
+	private void parseConstructor(Element apiConstructorElement, String contextClassName, StringBuilder functionBuilder)
+			throws Exception {
+		String constructorName = contextClassName != null ? contextClassName
+				: apiConstructorElement.element("apiName").getTextTrim();
+
+		String access = null;
+
+		Element apiConstructorDetailElement = apiConstructorElement.element("apiConstructorDetail");
+		if (apiConstructorDetailElement == null) {
+			throw new Exception("apiConstructorDetail not found for: " + constructorName);
+		}
+		Element apiConstructorDefElement = apiConstructorDetailElement.element("apiConstructorDef");
+		if (apiConstructorDefElement == null) {
+			throw new Exception("apiConstructorDef not found for: " + constructorName);
+		}
+
+		Element apiAccessElement = apiConstructorDefElement.element("apiAccess");
+		if (apiAccessElement != null) {
+			access = apiAccessElement.attributeValue("value");
+		}
+
+		List<Element> apiParamElements = apiConstructorDefElement.elements("apiParam");
+
+		functionBuilder.append("\t");
+		if (access != null && access.length() > 0) {
+			functionBuilder.append(access);
+			functionBuilder.append(" ");
+		}
+		functionBuilder.append("native ");
+		functionBuilder.append("function ");
+		functionBuilder.append(constructorName);
+		functionBuilder.append("(");
+		parseParameters(apiParamElements, contextClassName, functionBuilder);
+		functionBuilder.append(")");
+		functionBuilder.append(";");
+		functionBuilder.append("\n");
+	}
+
+	private String parseReturnOrParamType(Element apiTypeElement, String contextClassName) throws Exception {
+		String apiTypeValue = apiTypeElement.attributeValue("value");
+		switch (apiTypeValue) {
+			case "restParam": {
+				return null;
+			}
+			case "any": {
+				return "*";
+			}
+			case "T": {
+				return "T";
+			}
+			case "void": {
+				return "void";
+			}
+			default:
+				if (apiTypeValue.startsWith("Vector$")) {
+					String[] parts = apiTypeValue.split("\\$");
+					String vectorItemType = parts[1];
+					vectorItemType = vectorItemType.replace(":", ".");
+					if (contextClassName != null && contextClassName.startsWith("Vector$")
+							&& vectorItemType.equals("T")) {
+						return contextClassName;
+					}
+					return "Vector.<" + vectorItemType + ">";
+				} else {
+					throw new Exception("Unknown apiType value: " + apiTypeValue);
+				}
+		}
+	}
+
+	private void parseParameters(List<Element> apiParamElements, String contextClassName, StringBuilder functionBuilder)
+			throws Exception {
+		for (int i = 0; i < apiParamElements.size(); i++) {
+			if (i > 0) {
+				functionBuilder.append(", ");
+			}
+			Element apiParamElement = apiParamElements.get(i);
+			Element apiTypeElement = apiParamElement.element("apiType");
+			String paramType = null;
+			if (apiTypeElement != null) {
+				String apiTypeValue = apiTypeElement.attributeValue("value");
+				if ("restParam".equals(apiTypeValue)) {
+					functionBuilder.append("...");
+				}
+				paramType = parseReturnOrParamType(apiTypeElement, contextClassName);
+			}
+			Element apiItemNameElement = apiParamElement.element("apiItemName");
+			if (apiItemNameElement == null) {
+				throw new Exception("apiItemName not found");
+			}
+			functionBuilder.append(apiItemNameElement.getTextTrim());
+			Element apiOperationClassifierElement = apiParamElement.element("apiOperationClassifier");
+			if (apiOperationClassifierElement != null) {
+				paramType = apiOperationClassifierElement.getTextTrim();
+				paramType = paramType.replace(":", ".");
+			}
+			if (paramType != null) {
+				functionBuilder.append(":");
+				functionBuilder.append(paramType);
+			}
+			Element apiDataElement = apiParamElement.element("apiData");
+			if (apiDataElement != null) {
+				writeVariableOrParameterValue(apiDataElement, paramType, functionBuilder);
+			}
+		}
+	}
+
+	private void writeVariableOrParameterValue(Element apiDataElement, String varType, StringBuilder builder) {
+		builder.append(" = ");
+		String paramValue = apiDataElement.getTextTrim();
+		if ("unknown".equals(paramValue)) {
+			paramValue = "null";
+		}
+		boolean isString = ("String".equals(varType) || paramValue.matches("[A-Za-z]+")) && !"null".equals(paramValue)
+				&& !"NaN".equals(paramValue) && !"true".equals(paramValue) && !"false".equals(paramValue);
+		if (isString) {
+			builder.append("\"");
+		}
+		builder.append(paramValue);
+		if (isString) {
+			builder.append("\"");
+		}
+	}
+
+	private void collectImport(String fullyQualifiedName, String forPackage, Set<String> result) throws Exception {
+		String[] parts = fullyQualifiedName.split(":");
+		if (parts.length == 1) {
+			//top-level package
+			return;
+		}
+		String packageName = parts[0];
+		if (packageName.equals(forPackage)) {
+			//same package
+			return;
+		}
+		result.add(packageName + "." + parts[1]);
+	}
+
+	private void collectImports(Element element, String forPackage, Set<String> result) throws Exception {
+		switch (element.getName()) {
+			case "apiClassifier": {
+				String className = element.element("apiName").getTextTrim();
+
+				Element apiClassifierDetailElement = element.element("apiClassifierDetail");
+				if (apiClassifierDetailElement == null) {
+					throw new Exception("apiClassifierDetail not found for: " + className);
+				}
+				Element apiClassifierDefElement = apiClassifierDetailElement.element("apiClassifierDef");
+				if (apiClassifierDefElement == null) {
+					throw new Exception("apiClassifierDef not found for: " + className);
+				}
+
+				Element apiBaseClassifierElement = apiClassifierDefElement.element("apiBaseClassifier");
+				if (apiBaseClassifierElement != null) {
+					String baseClassType = apiBaseClassifierElement.getTextTrim();
+					collectImport(baseClassType, forPackage, result);
+				}
+
+				List<Element> apiBaseInterfaceElements = apiClassifierDefElement.elements("apiBaseInterface");
+				for (Element apiBaseInterfaceElement : apiBaseInterfaceElements) {
+					String interfaceType = apiBaseInterfaceElement.getTextTrim();
+					collectImport(interfaceType, forPackage, result);
+				}
+
+				Element apiConstructorElement = element.element("apiConstructor");
+				if (apiConstructorElement != null) {
+					collectImports(apiConstructorElement, forPackage, result);
+				}
+
+				List<Element> apiOperationElements = element.elements("apiOperation");
+				for (Element apiOperationElement : apiOperationElements) {
+					collectImports(apiOperationElement, forPackage, result);
+				}
+
+				List<Element> apiValueElements = element.elements("apiValue");
+				for (Element apiValueElement : apiValueElements) {
+					collectImports(apiValueElement, forPackage, result);
+				}
+
+				break;
+			}
+			case "apiOperation": {
+				String functionName = element.element("apiName").getTextTrim();
+
+				Element apiOperationDetailElement = element.element("apiOperationDetail");
+				if (apiOperationDetailElement == null) {
+					throw new Exception("apiOperationDetail not found for: " + functionName);
+				}
+				Element apiOperationDefElement = apiOperationDetailElement.element("apiOperationDef");
+				if (apiOperationDefElement == null) {
+					throw new Exception("apiOperationDef not found for: " + functionName);
+				}
+
+				Element apiReturnElement = apiOperationDefElement.element("apiReturn");
+				if (apiReturnElement != null) {
+					Element apiTypeElement = apiOperationDefElement.element("apiType");
+					if (apiTypeElement != null) {
+						String apiTypeValue = apiTypeElement.attributeValue("value");
+						if (apiTypeValue.startsWith("Vector$")) {
+							String[] parts = apiTypeValue.split("\\$");
+							String vectorItemType = parts[1];
+							collectImport(vectorItemType, forPackage, result);
+						}
+					}
+					Element apiOperationClassifierElement = apiReturnElement.element("apiOperationClassifier");
+					if (apiOperationClassifierElement != null) {
+						String returnType = apiOperationClassifierElement.getTextTrim();
+						collectImport(returnType, forPackage, result);
+					}
+				}
+
+				List<Element> apiParamElements = apiOperationDefElement.elements("apiParam");
+				for (Element apiParamElement : apiParamElements) {
+					Element apiTypeElement = apiParamElement.element("apiType");
+					if (apiTypeElement != null) {
+						String apiTypeValue = apiTypeElement.attributeValue("value");
+						if (apiTypeValue.startsWith("Vector$")) {
+							String[] parts = apiTypeValue.split("\\$");
+							String vectorItemType = parts[1];
+							collectImport(vectorItemType, forPackage, result);
+						}
+					}
+					Element apiOperationClassifierElement = apiParamElement.element("apiOperationClassifier");
+					if (apiOperationClassifierElement != null) {
+						String paramType = apiOperationClassifierElement.getTextTrim();
+						collectImport(paramType, forPackage, result);
+					}
+				}
+				break;
+			}
+			case "apiConstructor": {
+				String functionName = element.element("apiName").getTextTrim();
+
+				Element aapiConstructorDetailElement = element.element("apiConstructorDetail");
+				if (aapiConstructorDetailElement == null) {
+					throw new Exception("apiConstructor not found for: " + functionName);
+				}
+				Element apiConstructorDefElement = aapiConstructorDetailElement.element("apiConstructorDef");
+				if (apiConstructorDefElement == null) {
+					throw new Exception("apiConstructorDef not found for: " + functionName);
+				}
+
+				List<Element> apiParamElements = apiConstructorDefElement.elements("apiParam");
+				for (Element apiParamElement : apiParamElements) {
+					Element apiTypeElement = apiParamElement.element("apiType");
+					if (apiTypeElement != null) {
+						String apiTypeValue = apiTypeElement.attributeValue("value");
+						if (apiTypeValue.startsWith("Vector$")) {
+							String[] parts = apiTypeValue.split("\\$");
+							String vectorItemType = parts[1];
+							collectImport(vectorItemType, forPackage, result);
+						}
+					}
+					Element apiOperationClassifierElement = apiParamElement.element("apiOperationClassifier");
+					if (apiOperationClassifierElement != null) {
+						String paramType = apiOperationClassifierElement.getTextTrim();
+						collectImport(paramType, forPackage, result);
+					}
+				}
+				break;
+			}
+			case "apiValue": {
+				String variableName = element.element("apiName").getTextTrim();
+
+				Element apiValueDetailElement = element.element("apiValueDetail");
+				if (apiValueDetailElement == null) {
+					throw new Exception("apiValueDetail not found for: " + variableName);
+				}
+				Element apiValueDefElement = apiValueDetailElement.element("apiValueDef");
+				if (apiValueDefElement == null) {
+					throw new Exception("apiValueDef not found for: " + variableName);
+				}
+
+				Element apiValueClassifierElement = apiValueDefElement.element("apiValueClassifier");
+				if (apiValueClassifierElement != null) {
+					String variableType = apiValueClassifierElement.getTextTrim();
+					collectImport(variableType, forPackage, result);
+				}
+				break;
+			}
+		}
+	}
+
+	private void writeImports(Set<String> imports, StringBuilder builder) {
+		for (String importName : imports) {
+			builder.append("\t");
+			builder.append("import ");
+			builder.append(importName);
+			builder.append(";");
+			builder.append("\n");
+		}
+		if (imports.size() > 0) {
+			builder.append("\n");
+		}
+	}
+}
\ No newline at end of file