build4code
Version:
The repository supports the NPM build process based on UML models created and managed with the JSONEditor4Code. A JSON file defines the attributes and methods of a class and a JSON editor running in a browser allows the generation of Javascript code. In t
444 lines (360 loc) • 24.2 kB
Markdown
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Build4Code](#build4code)
- [Installation](#installation)
- [Install `build4code`](#install-build4code)
- [Sample Script `build.js`, `files4build.js`](#sample-script-buildjs-files4buildjs)
- [Example `build4code`](#example-build4code)
- [Build Replacements with Package.json Content](#build-replacements-with-packagejson-content)
- [Alteration of `package.json`](#alteration-of-packagejson)
- [Create `build.js` script with Concatenation](#create-buildjs-script-with-concatenation)
- [Build `build.js` with `terser`](#build-buildjs-with-terser)
- [JavaScript to UML Converter](#javascript-to-uml-converter)
- [JS2UML Parameters of `js2uml` in package.json](#js2uml-parameters-of-js2uml-in-packagejson)
- [Defaults und Filename for UML file in JSON format](#defaults-und-filename-for-uml-file-in-json-format)
- [Prototype Defintions of Method](#prototype-defintions-of-method)
- [Call `js2uml()` Javascript to UML Converter](#call-js2uml-javascript-to-uml-converter)
- [Missing Constructors for JS2UML](#missing-constructors-for-js2uml)
- [UML for static Javascript Objects](#uml-for-static-javascript-objects)
- [Folder and Files in Repository](#folder-and-files-in-repository)
- [Folder `dist/`](#folder-dist)
- [File `build.js`](#file-buildjs)
- [Folder `docs/`](#folder-docs)
- [Folder `src/`](#folder-src)
- [Folder `src/css`](#folder-srccss)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Build4Code
Build4Code supports the build process for HTML, CSS, Javascript, README and UML models.
According to UML the repository supports the NPM build process based on UML models created and managed with the JSONEditor4Code. A JSON file defines the attributes and methods of a class and a JSON editor running in a browser allows the generation of Javascript code.
## Installation
If you want to use `build4code` install the package with `npm`:
### Install `build4code`
Install `build4code` with the follwing npm commands
```
npm install build4code --save-dev`
```
The package `build4code` needs two files to work.
* `build.js` script that is called with `npm run build`
* `files4build.js` defines the parts for HTML, CSS, Javascript libraries for concatenation.
### Sample Script `build.js`, `files4build.js`
Some sample scripts are available in the following repositories:
* Repository `LoadFile4DOM`: https://www.gitlab.com/niehausbert/loadfile4dom
* Repository `JSONEditor4Menu`: https://www.gitlab.com/niehausbert/jsoneditor4menu
## Example `build4code`
The GitLab package `loadfile4dom` provides an example build script [`build.js`](https://gitlab.com/niehausbert/loadfile4dom/blob/master/build.js) which uses `build4code` to generate the CSS, Javascript and README file with `npm run build`. The file [`files4build.js`](https://gitlab.com/niehausbert/loadfile4dom/blob/master/files4build.js). The `package.json` of the library LoadFile4DOM call the build script `build.js` (see [`package.json`](https://gitlab.com/niehausbert/loadfile4dom/blob/master/package.json) for details).
The module `build4code` uses the sources in the folder [`src/`](https://gitlab.com/niehausbert/loadfile4dom/tree/master/src) for building the files in the module. It creates the
* `README.md` from `src/readme`,
* the Javascript files in `dist/` for application in a browser from `src/libs` and
* `CSS` file as concatenation of `src/css`.
The output filenames for the file bundles are defined in the [`package.json`](https://gitlab.com/niehausbert/loadfile4dom/blob/master/package.json) of the repository which uses `build4code`.
## Build Replacements with Package.json Content
In many cases it is required to add dynamic content from the file `package.json` to the generated files.
* version number of the library,
* package name,
* Git user name in GitLab or GitHub.
```javascript
const pkg = require('./package.json');
// or
let pkg = {
"name":"handlebars4code",
"version": "0.1.8",
"exportvar":"Handlebars4Code",
"gituser":"niebert",
"bugs": {
"url": "https://github.com/niebert/HandleBars4Code/issues"
},
}
```
These variables in the `package.json` will allow to use the following variables in the source files in the folder `src/` of the repository that uses `build4code` (e.g. in [`loadfile4dom`](https://gitlab.com/niehausbert/loadfile4dom/) repository).
* `___PKG_NAME___` will be replaced by the value of `pkg.name` e.g. by `handlebars4code`
* `___PKG_VERSION___` will be replaced by the value of `pkg.version` e.g. by `0.1.8`
* `___PKG_EXPORTVAR___` will be replaced e.g. by the value of `pkg.exportvar` e.g. by `handlebars4code`
* `___PKG_GITUSER___` will be replaced e.g. by the value of `pkg.name` e.g. by `handlebars4code`.
* `___PKG_URL4ZIP___` `pkg.url4zip` stores the URL for downloading the ZIP file of the repository.
* `___PKG_URL4WWW___` `pkg.url4www` stores the URL to the web resouce of the repository.
* `___PKG_URL4REPO___` `pkg.url4repo` stores the URL to the `git` repository.
* `___PKG_DATETIME___` `pkg.datetime` stores the current date and time as a time stamp for the build of the repository. The marker can be used in source code, `README.md` and HTML files that are generated from the files in the `src/` directory of the repository.
Some parts of file `README.md` may be used with slight modifications in many repositories. Instead of writing these parts for `README.md` for each repository separately you can define a file part in `src/readme` that looks like this:
```
Just download the [ZIP-file of the ___PKG_EXPORTVAR___ repository](___PKG_URL4ZIP___)
for the repository `___PKG_NAME___` version ___PKG_VERSION___ and
start the file `docs/index.html` in your browser.
Build data/time: `___PKG_DATETIME___`
const ___PKG_EXPORTVAR___ = require('__PKG_NAME__');
Demo URL: ___PKG_URL4WWW___
Demo Repository: ___PKG_URL4REPO___
```
After running `build4code` the generated `README.md` will contain the expanded code. With the example `package.json` mentioned above. Markdown of `README.md` will look like this:
```
Just download the [ZIP-file of the Handlebars4Code repository](https://github.com/niebert/HandleBars4Code/archive/master.zip)
for the repository `handlebars4code` version 0.1.8
and start the file `docs/index.html` in your browser.
Build data/time: `2019/08/16 8:23`
const Handelbars4Code = require('handelbars4code');
Demo URL: https://niebert.github.io/niebert/HandleBars4Code/
Demo Repository: https://www.github.com/niebert/Handlebars4Code
```
### Alteration of `package.json`
Insert the following script call in `package.json`:
The script section may look like this:
```json
"name":"my_package",
"exportvar":"MyPackage",
"gituser":"myusername",
"url4www":"https://myusername.github.io/my_packager",
"url4zip":"https://wgithub.com/myusername/my_package/archive/master.zip",
"url4repo":"https://www.github.com/myusername/my_package",
"scripts": {
"watch": "watchify src/main.js -o dist/my_package.js -v",
"browserify": "browserify src/main.js > dist/my_package.js",
"build2dist": "node ./build.js; browserify src/main.js > docs/js/my_package.js",
"buildmin": "uglifyjs dist/my_package.js --compress -o dist/jsoneditor4menu.min.js",
"test": "jshint dist/my_package.js",
"build": "node ./build.js; browserify src/main.js > docs/js/my_package.js.js",
"compress": "node ./build.js;browserify docs/js/my_package.js | uglifyjs -mc warnings=false > dist/my_package.min.js"
},
```
### Create `build.js` script with Concatenation
If you use this build process it assumes that the package is decomposed into different files for better maintenance.
The build process concatenates these parts into one file and adds version banners in front of the compressed and uncompressed files.
Create a file `build.js` in the folder of your `npm` module.
If your package is stored in the directory `my_package/` create the file `my_package/build.js` with the following structure. It assumes that the file `package.json` is created and located in this folder at `my_package/package.json`:
```javascript
const pkg = require('./package');
const b4c = require('build4code');
// ------ Build Settings -----------------
var vExportVar = pkg.exportvar; // defined in package.json as "exportvar"
var vSrcPath = "./src/"; // Path to Source Libraries
var vDistPath = "./dist/"; // Path to distribution
var vLibPath = vSrcPath + 'libs/';
var vLibDist = '/'+pkg.name+'.js';
var vLibOut = './docs/js/'+pkg.name+'.js';
var vLibArray = [
'./src/npm_header.js',
vLibPath+'arrayhash.js',
vLibPath+'blob.js',
vLibPath+'bootstrap.js',
vLibPath+'classeditor.js',
vLibPath+'date.js',
vLibPath+'savefile.js',
vLibPath+'filesaver.js',
vLibPath+'handlebars4code.js',
vLibPath+'node_modules/jsoneditor/dist/jsoneditor.js',
vLibPath+'linkparam.js',
//vLibPath+'localstorage.js',
vLibPath+'exportmod.js'
];
// ----------------------------------------
// Process Chaining
// (1) create "npm_header.js" and "npm_tail.js" in src/libs
// (2) concat files export library to docs/js with prepend npm_header.js
// (3) create src/main.js for browserify and append "npm_tail.js"
var codegen = b4c.codegen;
pkg.exportvar = vExportVar;
codegen.create_header(pkg);
//codegen.create_inherit_static(pkg);
codegen.create_tail(pkg);
codegen.concat_main(pkg.main,vLibArray,pkg);
codegen.concat_libs(vLibOut,vLibArray,pkg);
codegen.concat_libs(vLibDist,vLibArray,pkg);
```
### Build `build.js` with `terser`
[`terser`](https://github.com/terser-js/terser) JavaScript parser and mangler/compressor toolkit for [ES6+](http://es6-features.org).
```javascript
const pkg = require('./package');
const b4c = require('build4code');
const buildjs = b4c.build4wtf;
// ------ Build Settings -----------------
var vExportVar = pkg.exportvar; // defined in package.json as "exportvar"
var vSrcPath = "./src/"; // Path to Source Libraries
var vDistPath = "./dist/"; // Path to distribution
var vLibPath = vSrcPath + 'libs/';
var vLibDist = './dist/'+pkg.name+'.js';
var vLibOut = './docs/js/'+pkg.name+'.js';
buildjs(vSrcPath + "index.js","./package.json",vDistPath);
```
## Replace Version and Time Stamps in HTML
For WebApps you might want to replace version and timestamps in HTML code. E.g. in a file `docs/index.html` you can do this with:
```javascript
const fs = require("fs");
const pkg = require("./package.json");
const b4c = require("build4code").codegen;
// replace <div id4marker="version">2.0.2</div> with current version
console.log("Set version build.js for '" + pkg.name + "' version "+pkg.version);
var outfile = "undefined content";
fs.readFile('docs/index.html', 'utf8', function readFileCallback(err, data){
if (err){
console.log(err);
} else {
outfile = b4c.replace_version(data);
}
});
setTimeout(function () { b4c.save_file('docs/index.html', outfile); },1500);
```
It assumes tags for the time stamp and the version in the following format:
```html
<span id4marker="version">1.4.14</span>
for any position in the HTML file, where you want to update the version and the following HTML tag, where you want to update the time stamp in the version with the current date and time.
```html
<span id4marker="datetime">2021/01/04 9:47:55</span>
```
## JavaScript to UML Converter
The JavaScript to UML converter is part of the `build2code` repository. It is used to create UML model of a Javascript code. The script `js2uml` reads a JavaScript library and generates a JSON file in the folder `jscc/` (JavaScript Classs Creator), that represents the UML of the library. You can load the UML in the [ClassEditorUML](https://niebert.github.io/ClassEditorUML) and from there you can update the UML definition and provide comments for attributes, methods and paramters of the UML class. [ClassEditorUML](https://niebert.github.io/ClassEditorUML) is able to generate JavaScript code with updated content and GitLab/GitHub markdown documentation for e.g. `README.md`.
The following section will describe, how the JSON file with the UML structure can be generated from a given code in the directory `/src/libs` and used in an UML Editor for Javascript sources.
### JS2UML Parameters of `js2uml` in package.json
`js2uml` is able to identify the defined methods of a class.
Assume you defined a Javascript class `myclass.js` the file `package.json` requires an attribute to provide the parameters for `js2uml`:
```json
"js2uml": {
"default": "jscc/myclass_default.json",
"filename": "jscc/myclass_uml.json",
"constructor": true
}
```
If the classname (`exportvar` in package.json) is a constructor, set the boolean in `js2uml.constructor=true`. It is a constructor, if you call the `exportvar` with the Javascript command `new` e.g.
```javascript
var my_class = new MyClass();
```
#### Defaults und Filename for UML file in JSON format
The Javascript to UML compliler `js2uml` does not extract comments from Javascript because it is not possible to distinguish between ordinary Javascript comments and Javascript comments for methods and attributes. So if method `my_method()` or an attribute `my_attribute` is recognized in the javascript code, `js2uml` checks if appropriate comments are defined already in the previous version or default version of `myclass_uml.json`. You can set `js2uml.default` and `js2uml.filename` to the same filename if everything runs smoothly. For debugging it it recommended to used different filename for default/input and filename/output.
#### Prototype Defintions of Method
The most common application of defining methods is the prototype definition of methods. Assume we define a Javascript class `MyClass` - see example [`LoadFile4DOM`](https://www.gitlab.com/niehausbert/loadfile4dom). Now we define the method `my_method()` as prototype.
```javascript
function MyClass () {
// Constructor called with new MyClass()
// ...
}
MyClass.prototype.my_method = function (pPar1,pPar2) {
// code for the method "mymethod"
}
```
#### Call `js2uml()` Javascript to UML Converter
The function `js2uml()` needs the following input parameters.
* (`pUML`) a JSON for a the Javascript class that represents the previous representation of UML (e.g. `myclass_uml.json`). The JSON `pUML` is usually generated with [ClassEditorUML](https://niebert.github.io/ClassEditorUML). The previous UML definition of the class will be updated by `js2uml()` (e.g. code bodies and parameters of methods are updated from the source Javascript file e.g. `myclass.js`). Bugfixing of the code is usually performed in an editor like [Atom](https://atom.io/) and the general structure of a Javascript class during software design is done in an UML editor. `js2uml()` will use from the input `UML` file to take previously defined comments for
* attributes,
* methods and
* parameters of methods (functions)
maps those comments to the parsed UML structure.
* (`vConstructor`) as a reference to the defined attributes of constructor (e.g. `pConstructor=MyClass`).
* the `UML` output filename is defined in `package.json`. This filename is used to store the UML file in JSON format after the call of `js2uml()`
* (`pkg`) the required JSON `package.json`.
You can call the `js2uml()` within a build script for code generation with the following commands.
```javascript
const pkg = require('./package.json')
// const b4c = require('build4code');
const b4c = require('build4code');
let vConstructor = require('./src/index.js');
// UML filename contains the output filename
pkg.js2uml.filename = 'jscc/codegen_uml.json';
pkg.js2uml.is_constructor = true;
let vClassname = "MyClass";
b4c.js2uml(vClassname,vConstructor,pkg);
```
If the Javascript class is a constructor function called with `new` then method are scanned in `MyClass.prototype`.
If the loaded javascript `js2uml` scans all attributes of the hash pushes functions and the defined code to the methods of `MyClass` and other attributes like arrays, numbers, strings, boolean, .... to the attributes:
```javascript
function MyClass () {
this.my_attribute1 = 0.0;
this.my_method2 = function (pPar1,pPar2) {
// code of my_method1 ...
}
}
MyClass.prototype.my_method1 = function (pPar1,pPar2) {
// code of my_method2 ...
}
```
`my_method1()` is defined as prototype, while `my_method2()` will consume memory for the method for any created instance of `MyClass`. As an example we create 2 new instances of `MyClass`.
```javascript
var my_inst1 = new MyClass();
var my_inst2 = new MyClass();
```
If you define methods in constructor is not recommended, unless you want overwrite the methods individually for each instance of `MyClass`. Then define e.g. the method `my_method1()` like this:
```javascript
function MyClass () {
this.my_attribute1 = 0.0;
this.my_method1 = function (pPar1,pPar2) {
// code of my_method1 ...
}
}
```
#### Missing Constructors for JS2UML
If you the class uses other libraries like `JQuery` `JSZip`, `LinkParam` and these libraries are used with an input tag in the `HTML` file, then the constructors like `JSZip` or `LinkParam` resp. the Object `$` of JQuery is not available, when the constructor is required before the `js2uml()` call.
For these DOM objects it is necessary to insert dummy functions and DOM objects like `document` and `window`, with the library `jsdom`. If you access the `document` and `window` add as missing library `JQuery`, then these objects are emulated by `jsdom` and the require command for the constructor is not complaining anymore.
Assume your class needs the following libraries to operate, then call the `create_constructor()` command with the following parameter:
```javascript
var vCode = codegen.load_file('./src/myclass.js');
// add objects for imported libraries in index.html for ["JQuery","LinkParam","JSZip"]
vCode = codegen.create_constructor("./jscc/constructor.js",vCode,["JQuery","LinkParam","JSZip"], pkg);
```
After that call you will have a file `jscc/constructor.js` for the `js2uml()` call. See also build script in repository `JSONEditor4Menu` - URL: https://www.gitlab.com/niehausbert/jsoneditor4menu
Take care that the following libraries resp. NPM modules are installed:
```
npm install jsdom --save-dev
npm install jquery --save
npm install linkparam --save
npm install jszip --save
```
### UML for static Javascript Objects
Above descriptions assume that the parse Javascript object for `js2uml` is a constructor.
The constructor could also be also just a hash of functions.
```json
"js2uml": {
"default": "jscc/mylib_default.json",
"filename": "jscc/mylib_uml.json",
"constructor": false
}
```
Assume we have create a library `mylib.js` for a NPM module `mylib`. The `package.json` contains the `js2uml` section above.
The source file `mylib.js` will look like this:
```javascript
let vHash = {
"my_height": 174.0,
"my_name": "Bert",
"my_method1": function (pPar1,pPar2) {
// code of my_method1 ...
}
};
module.exports = vHash;
```
Building the UML file in JSON format for the [ClassEditorUML](https://niebert.github.io/ClassEditorUML) can be performed like this.
```javascript
const pkg = require('./package.json')
// const b4c = require('build4code');
const b4c = require('build4code');
const vModule = require("./mylib.js");
// vUML_filename contains the output filename
pkg.js2uml.filename = 'jscc/mylib_uml.json';
let vHashname = "MyHash";
b4c.js2uml(vHashname,vModule,pkg);
```
An example for such as static class is `Handlebars`.
You can use the template engine `Handlebars` just with `require` command an without creating a new instance with `new Handlebars()`. Nevertheless the document can be parsed and converted in the UML model as "static class" in Javascript.
If we extend the `Handelbars` module to `Handlebars4Code`, it is necessary to scan the static super class `Handelbars` and the `Handlebars4Code` static class so that only the new defined methods and attributes are displayed in the UML export for `hash2uml()`.
Currently the `include_overwrite` array lists all functions in `Handelbars` that will be overwritten in `Handlebars4Code`. The listed methods will be stored in the `include_overwrite` array and the list of methods will be included in the UML export. The options is currently necessary because there is no solution yet to identify, if a function is overwritten without modifying the source code of the static classes. [ClassEditorUML](https://niebert.github.io/ClassEditorUML) has a setting in the JSON schema of the repository to declare a JavaScript class as `static`. The option will be set by `js2uml()` automatically.
Currently the `include_overwrite` array lists all functions in `Handelbars` that will be overwritten in `Handlebars4Code`. The listed methods will be stored in the `include_overwrite` array and the list of methods will be included in the UML export. The options is currently necessary because there is no solution yet to identify, if a function is overwritten without modifying the source code of the static classes. [ClassEditorUML](https://niebert.github.io/ClassEditorUML) has a setting in the JSON schema of the repository to declare a JavaScript class as `static`. The option will be set by `js2uml()` automatically.
## Folder and Files in Repository
In the repository `package.json` an attribute `exportvar` is defined (resp. must be added to the `package.json` for the buildprocess. Several files are generated automatically during the build process and especially the constructor uses the value of `exportvar` for the automated generation of the documentation. Furthermore `files4build.js` defines the list of files parts that are required and used to run the build process with `npm run build`. The
### Folder `dist/`
The folder `dist/` contains all generated libraries by `npm run build` which calls `build.js`. The function `getLibs4Build()` (defined in `files4build.js`) return and array of files that are concatenated for generating the libraries `dist/my_package.js` and `dist/my_package.min.js`
### File `build.js`
Assume the package name in `npm` is `my_package`. The following documentation refers to this package name. Depending on the package name the files are created.
The file `build.js` creates the files for the repository in `JS`, `HTML`, `CSS`, `README`:
* `README.md` of the reporsitory with file parts in `src/readme`
* `JS`: `dist/my_package.js` as main library for distribution with file parts in `src/libs`.
* `JS`: `dist/my_package.min.js` as compressed main library for distribution with file parts in `src/libs` - compressed with `UglifyJS`.
* `HTML`: `docs/index.html` for the repository with file parts in `src/html`.
* `JS`: `docs/js/my_package.js` as main library for web demo in `docs/` with file parts in `src/html/`.
* `CSS`: `docs/css/main.js` as main library for web demo in `docs/` with file parts in `src/css/`.
**Remark:** DO NOT EDIT the following generated files of the build process with `build.js` directly
* `my_package.js`,
* `my_package.min.js`,
* `docs/index.html`,
* `css/main.css`
because your work will be lost after running `npm run build` again. Edit the source files for the build process in the folder `src/` instead.
### Folder `docs/`
The folder `docs/` contains all files for the web demo of this repository e.g. on `GitHub`, that can be accessed to the `https://myusername.github.io/my_package` with a the username `myusername` on GitHub.
### Folder `src/`
The folder `src/` contains all source files for the build process defined by `build.js` in this repository. `files4build.js` defines the list of files parts that are required and used to the build process with `npm run build`.
#### Folder `src/css`
The folder `src/css` contains all `CSS` source files for the build process defined by `build.js` in this repository. `files4build.js` defines the list of files parts that are required and used to the build process with `npm run build`.