Added angular-librarian for manage library

This commit is contained in:
Lorenzo Iovino 2017-11-14 11:07:08 +01:00
parent 9d174550f5
commit e625f9fd30
44 changed files with 1867 additions and 228 deletions

1
.erector Normal file
View file

@ -0,0 +1 @@
[{"name":"name","answer":"ng2-fittext"},{"name":"packageName","answer":"ng2-fittext"},{"name":"readmeTitle","answer":"Ng2 Fittext"},{"name":"repoUrl","answer":"https://github.com/lokenxo/ng2-fittext"},{"name":"git","answer":""},{"name":"moduleName","answer":"Ng2FittextModule"},{"name":"version","answer":"1.0.25"}]

17
.gitignore vendored
View file

@ -1,11 +1,6 @@
# Node generated files
node_modules
npm-debug.log
# OS generated files
Thumbs.db
.DS_Store
# Ignored files
*.js
*.map
*.d.ts
.idea
build
coverage
dist
debug.log
node_modules
out-tsc

12
.idea/fittext2.iml generated Normal file
View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="TsLint" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/fittext2.iml" filepath="$PROJECT_DIR$/.idea/fittext2.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

249
.idea/workspace.xml generated Normal file
View file

@ -0,0 +1,249 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="6d9e6998-eced-4f47-8fb4-3257db3e18e7" name="Default" comment="" />
<ignored path="$PROJECT_DIR$/.tmp/" />
<ignored path="$PROJECT_DIR$/temp/" />
<ignored path="$PROJECT_DIR$/tmp/" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="ng2-fittext.directive.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/directives/ng2-fittext.directive.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-270">
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="README.md" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor relative-caret-position="2430">
<caret line="120" column="9" lean-forward="false" selection-start-line="120" selection-start-column="9" selection-end-line="120" selection-end-column="9" />
<folding />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="package.json" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/package.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="221">
<caret line="76" column="24" lean-forward="true" selection-start-line="76" selection-start-column="24" selection-end-line="76" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="tsconfig.json" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/tsconfig.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="ng2-fittext.module.ts" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/ng2-fittext.module.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="108">
<caret line="6" column="22" lean-forward="false" selection-start-line="6" selection-start-column="22" selection-end-line="6" selection-end-column="22" />
<folding>
<element signature="e#0#47#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/src/ng2-fittext.module.ts" />
<option value="$PROJECT_DIR$/src/directives/ng2-fittext.directive.ts" />
<option value="$PROJECT_DIR$/README.md" />
<option value="$PROJECT_DIR$/package.json" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER">
<package-json value="$PROJECT_DIR$/package.json" />
</component>
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="NodeModulesDirectoryManager">
<handled-path value="$PROJECT_DIR$/node_modules" />
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="285" />
<option name="width" value="1598" />
<option name="height" value="1038" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="fittext2" type="b2602c69:ProjectViewProjectNode" />
<item name="fittext2" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="Scratches" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="settings.editor.selected.configurable" value="configurable.group.appearance" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="nodejs_interpreter_path" value="C:/Program Files/nodejs/node" />
<property name="HbShouldOpenHtmlAsHb" value="" />
<property name="node.js.path.for.package.tslint" value="project" />
<property name="node.js.detected.package.tslint" value="true" />
<property name="node.js.selected.package.tslint" value="C:\Users\loke\Work\mylib\fittext2\node_modules\tslint" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="6d9e6998-eced-4f47-8fb4-3257db3e18e7" name="Default" comment="" />
<created>1510652992413</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1510652992413</updated>
<workItem from="1510652993603" duration="653000" />
</task>
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="653000" />
</component>
<component name="ToolWindowManager">
<frame x="-9" y="-9" width="1938" height="1048" extended-state="6" />
<layout>
<window_info id="TypeScript" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.20465362" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="npm" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="true" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.32915717" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager />
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/src/ng2-fittext.module.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="108">
<caret line="6" column="22" lean-forward="false" selection-start-line="6" selection-start-column="22" selection-end-line="6" selection-end-column="22" />
<folding>
<element signature="e#0#47#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/directives/ng2-fittext.directive.ts">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="-270">
<caret line="6" column="0" lean-forward="false" selection-start-line="6" selection-start-column="0" selection-end-line="6" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/tsconfig.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.md">
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
<state split_layout="SPLIT">
<first_editor relative-caret-position="2430">
<caret line="120" column="9" lean-forward="false" selection-start-line="120" selection-start-column="9" selection-end-line="120" selection-end-column="9" />
<folding />
</first_editor>
<second_editor />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/package.json">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="221">
<caret line="76" column="24" lean-forward="true" selection-start-line="76" selection-start-column="24" selection-end-line="76" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
</component>
</project>

View file

@ -1,7 +1,24 @@
# Node generated files
*.spec.ts
*.tgz
.erector
.gitignore
.npmignore
.vscode
build
coverage
debug.log
DEVELOPMENT.md
dist
index.ts
karma.conf.js
node_modules
npm-debug.log
# OS generated files
Thumbs.db
.DS_Store
# Ignored files
out-tsc
src
tasks
test.ts
tsconfig.*json
tslint.json
typings
typings.json
vendor.ts
webpack

120
DEVELOPMENT.md Normal file
View file

@ -0,0 +1,120 @@
# Developing Ng2 Fittext
## Tasks
The following commands are available through `npm run` (or, if configured
`ngl`):
Command | Purpose
--- | ---
build | Runs code through build process via Angular compiler (ngc)
g | Generate code files (see above)
lint | Verify code matches linting rules
start | Run Webpack's dev-server on project (can be run as `npm start`)
[test](#unit) | Execute unit tests (can be run as `npm test <type>`)
tagVersion | Creates tag for new version and publishes
## Adding External Scripts
To add an external script, add it with a `script-loader!` prefix to the
`scripts` array of `entry` in `webpack/webpack.dev.js` (for the dev server)
and add it to the files array of `karma.conf.js` (for testing).
An example, adding the file at `node_modules/ext-dep/dist/dep.min.js`:
```javascript
/** webpack.dev.js **/
module.exports = {
// other config
entry: {
app: [ path.resolve(rootDir, 'examples', 'example.main') ],
scripts: [
// this is the external script line
'script-loader!' + path.resolve(rootDir, 'node_modules/ext-dep/dep.min')
],
vendor: [ path.resolve(rootDir, 'src', 'vendor')],
styles: [ path.resolve(rootDir, 'examples', 'styles.scss') ]
},
// rest of config
};
/** karma.conf.js **/
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
// this is the external script line
'node_modules/hammerjs/hammer.min.js',
{ pattern: './src/test.js', watched: false }
],
// rest of config
});
};
```
## <a name="unit"></a>Unit Testing
Unit testing is done using Karma and Webpack. The setup is all done during the `initialize` command.
The provided testing commands will watch your files for changes.
The two following command is provided by default:
```shell
npm test <type>
```
This command calls the script at `tasks/test.js` and runs the Karma test runner to execute the tests.
Prior to running Karma, the `test` command looks for a command line argument, if the argument is known,
it will run the associated configuration, otherwise it will run the default configuration.
#### Configurations
Type | Testing TypeScript
--- | ---
default | Run through PhantomJS one time with no file watching
all | Run through Chrome & PhantomJS with files being watched & tests automatically re-run
headless| Run through PhantomJS with files being watched & tests automatically re-run
watch | Run through Chrome with files being watched & tests automatically re-run
Note that Chrome still requires a manual refresh on the Debug tab to see updated test results.
## <a name="pack"></a>Packaging
Packaging is as simple as publishing to NPM by doing
```shell
npm run tagVersion
```
To test your packages output before publishing, you can run
```shell
npm pack
```
Which will generate a compressed file containing your library as it will look when packaged up and
published to NPM. The basic structure of a published library is:
```
|__bundles/
|__ng2-fittext.umd.js
|__ng2-fittext.umd.js.map
|__ng2-fittext.umd.min.js
|__ng2-fittext.bundle.min.js.map
|__index.d.ts
|__package.json
|__README.md
|__*.d.ts
|__ng2-fittext.d.ts
|__ng2-fittext.module.d.ts
|__ng2-fittext.es5.js
|__ng2-fittext.es5.js.map
|__ng2-fittext.js
|__ng2-fittext.js.map
|__ng2-fittext.metadata.json
```
As you can see, the packaging removes any files specific to developing your
library. It, more importantly, creates distribution files for usage with many
different module systems.

View file

View file

View file

@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
selector: 'example-root',
templateUrl: './example.component.html',
styleUrls: []
})
export class ExampleComponent { }

4
examples/example.main.ts Normal file
View file

@ -0,0 +1,4 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { ExampleModule } from './example.module';
platformBrowserDynamic().bootstrapModule(ExampleModule);

View file

@ -0,0 +1,18 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ExampleComponent } from './example.component';
import { Ng2FittextModule } from '../index';
@NgModule({
declarations: [
ExampleComponent
],
imports: [
BrowserModule,
Ng2FittextModule
],
providers: [],
bootstrap: [ExampleComponent]
})
export class ExampleModule { }

12
examples/index.html Normal file
View file

@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<title>Ng2FittextModule Tutorial</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<example-root>Loading...</example-root>
</body>
</html>

0
examples/styles.scss Normal file
View file

View file

@ -1 +1 @@
export {Ng2FittextModule} from './src/ng2fittext.module';
export * from './src';

113
karma.conf.js Normal file
View file

@ -0,0 +1,113 @@
'use strict';
const erectorUtils = require('erector-set/src/utils');
const fs = require('fs');
const path = require('path');
module.exports = function (config) {
const base = {
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: './src/test.js', watched: false }
],
mime: {
'text/x-typescript': ['ts','tsx']
},
plugins: [
'karma-chrome-launcher',
'karma-jasmine',
'karma-phantomjs-launcher',
'karma-coverage-istanbul-reporter',
'karma-sourcemap-loader',
'karma-webpack'
],
preprocessors: {
'./src/test.js': ['webpack', 'sourcemap']
},
coverageIstanbulReporter: {
dir: './coverage',
fixWebpackSourcePaths: true,
reports: ['html', 'lcovonly']
},
reporters: ['progress', 'coverage-istanbul'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome', 'PhantomJS'],
singleRun: false,
webpackServer: { noInfo: true }
};
const fullConfig = mergeCustomConfig(base, config);
config.set(fullConfig);
};
const mergeCustomConfig = (base, karmaConfig) => {
const customConfigPath = path.resolve(
__dirname,
'configs',
'karma.conf.js'
);
let fullConfig = base;
if (fs.existsSync(customConfigPath)) {
fullConfig = mergeConfigs(base, require(customConfigPath), karmaConfig);
}
return fullConfig;
};
const mergeConfigs = (base, custom, karmaConfig) => {
let mergedConfig = base;
if (erectorUtils.checkIsType(custom, 'function')) {
custom = custom(karmaConfig);
}
if (custom) {
const arrays = mergeConfigArrays(base, custom);
const objects = mergeConfigObjects(base, custom);
const primitives = mergeConfigPrimitives(base, custom);
const customAttributes = Object.assign({}, arrays, objects, primitives);
mergedConfig = Object.assign(
{}, base, customAttributes
);
}
return mergedConfig;
};
const mergeConfigArrays = (base, custom) => {
const attributes = ['browsers', 'files', 'plugins', 'reporters'];
return mergeConfigAttributes(base, custom, attributes, (baseAttribute, customAttribute) =>
erectorUtils.mergeDeep(baseAttribute, customAttribute)
);
};
const mergeConfigObjects = (base, custom) => {
const attributes = ['preprocessors'];
return mergeConfigAttributes(base, custom, attributes, (baseAttribute, customAttribute) =>
Object.assign(customAttribute, baseAttribute)
);
};
const mergeConfigPrimitives = (base, custom) => {
const attributes = ['color', 'logLevel', 'port'];
return mergeConfigAttributes(base, custom, attributes, (baseAttribute, customAttribute) =>
customAttribute
);
};
const mergeConfigAttributes = (base, custom, attributes, callback) => {
return attributes.reduce((config, attribute) => {
if (attribute in custom) {
config[attribute] = callback(base[attribute], custom[attribute]);
}
return config;
}, {});
};

View file

@ -1 +0,0 @@
export {Ng2FittextModule} from './src/ng2fittext.module';

View file

@ -1,43 +1,85 @@
{
"name": "ng2-fittext",
"version": "1.0.24",
"description": "An Angular2 directive for autoscale the font size of an element to fit an upper level container.",
"main": "index.js",
"description": "Ng2 Fittext, an Angular library",
"main": "./bundles/ng2-fittext.umd.js",
"module": "./ng2-fittext.es5.js",
"es2015": "./ng2-fittext.js",
"typings": "./ng2-fittext.d.ts",
"scripts": {
"prepublish": "tsc",
"test": "echo \"Error: no test specified\" && exit 1"
"build": "node ./tasks/build",
"g": "node ./node_modules/angular-librarian",
"lint": "tslint ./src/**/*.ts",
"postbuild": "rimraf build",
"posttagVersion": "npm run build && npm publish dist",
"prebuild": "rimraf dist out-tsc",
"start": "webpack-dev-server --open --config ./webpack/webpack.dev.js",
"tagVersion": "np --no-publish",
"test": "node ./tasks/test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/lokenxo/ng2-fittext.git"
},
"keywords": [
"angular2",
"ng2",
"fittext",
"ng2-fittext",
"responsivefont",
"ng-fittext angular2",
"angular2 fittext",
"ng2 fittext"
],
"author": "Lorenzo Iovino",
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/lokenxo/ng2-fittext/issues"
},
"homepage": "https://github.com/lokenxo/ng2-fittext#readme",
"peerDependencies": {
"@angular/core": ">=4.0.1",
"rxjs": "^5.4.0"
"dependencies": {
"@angular/common": "^4.0.0",
"@angular/compiler": "^4.0.0",
"@angular/core": "^4.0.0",
"@angular/platform-browser": "^4.0.0",
"@angular/platform-browser-dynamic": "^4.0.0",
"core-js": "^2.4.1",
"rxjs": "^5.0.1",
"zone.js": "0.8.12"
},
"devDependencies": {
"typescript": "~2.2.2"
"@angular/compiler-cli": "^4.0.0",
"@types/jasmine": "2.5.38",
"@types/node": "^6.0.42",
"angular-librarian": "1.0.0-beta.14",
"angular2-template-loader": "0.6.0",
"awesome-typescript-loader": "^3.0.0",
"codelyzer": "~3.0.0",
"css-loader": "^0.26.1",
"css-to-string-loader": "^0.1.3",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.8.5",
"fs-extra": "^2.1.2",
"html-webpack-plugin": "^2.19.0",
"istanbul-instrumenter-loader": "^1.2.0",
"jasmine-core": "2.5.2",
"jasmine-spec-reporter": "2.5.0",
"karma": "1.2.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage-istanbul-reporter": "^1.3.0",
"karma-jasmine": "^1.0.2",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.0",
"node-sass": "^4.1.1",
"np": "^2.12.0",
"phantomjs-prebuilt": "^2.1.7",
"raw-loader": "^0.5.1",
"rimraf": "^2.5.3",
"rollup": "0.43.0",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-node-resolve": "3.0.0",
"rollup-plugin-sourcemaps": "0.4.2",
"rollup-plugin-uglify": "2.0.1",
"sass-loader": "^4.0.1",
"script-loader": "^0.7.0",
"semver": "5.3.0",
"source-map-loader": "^0.1.5",
"style-loader": "^0.13.1",
"tslint": "^5.0.0",
"tslint-loader": "^3.0.0",
"typescript": "~2.2.1",
"typings": "^0.8.1",
"url-loader": "^0.5.7",
"webpack": "^2.2.0",
"webpack-dev-server": "^2.2.0",
"webpack-merge": "^0.14.0",
"webpack-node-externals": "^1.5.4"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"@angular/core": "^4.3.4"
"repository": {
"url": "https://github.com/lokenxo/ng2-fittext.git"
}
}

View file

@ -0,0 +1,15 @@
/* tslint:disable:no-unused-variable */
import {
async,
TestBed
} from '@angular/core/testing';
import { Ng2FittextDirective } from './ng2-fittext.directive';
describe('Ng2FittextDirective', () => {
it('', () => {
const directive = new Ng2FittextDirective();
expect(directive).toBeTruthy();
});
});

View file

@ -0,0 +1,134 @@
import {Directive, ElementRef, Renderer, Input, AfterViewInit, AfterViewChecked, HostListener, OnInit, OnChanges} from '@angular/core';
@Directive({
selector: '[fittext]'
})
export class Ng2FittextDirective implements AfterViewInit, OnInit, OnChanges, AfterViewChecked {
@Input('fittext') fittext: any;
@Input('activateOnResize') activateOnResize: boolean;
@Input('container') container: any;
@Input('activateOnInputEvents') activateOnInputEvents: boolean;
@Input('useMaxFontSize') useMaxFontSize: boolean;
@Input('minFontSize') minFontSize = 7;
@Input('modelToWatch') modelToWatch: any;
private maxFontSize = 1000;
private fontSize = 1000;
private speed = 1.05;
private done = false;
constructor(public el: ElementRef, public renderer: Renderer) { }
setFontSize(fontSize) {
if (this.isVisible() && this.done === false) {
if (fontSize < this.minFontSize) {
// force that font size will never be lower than minimal allowed font size
fontSize = this.minFontSize;
}
this.fontSize = fontSize;
return this.el.nativeElement.style.setProperty('font-size', (fontSize).toString() + 'px');
}
}
calculateFontSize(fontSize, speed) {
// TODO Do with Gauss
return Math.floor(fontSize / speed);
}
checkOverflow(parent: any, children: any) {
const overflowX = children.scrollWidth - parent.clientWidth;
const overflowY = children.clientHeight - parent.clientHeight;
return (overflowX > 1 || overflowY > 1);
}
@HostListener('window:resize', ['$event'])
onResize() {
this.done = false;
if (this.activateOnResize && this.fittext) {
if (this.activateOnInputEvents && this.fittext) {
this.setFontSize(this.getStartFontSizeFromHeight());
} else {
this.setFontSize(this.getStartFontSizeFromWeight());
}
this.ngAfterViewInit();
}
}
@HostListener('input', ['$event'])
onInputEvents() {
this.done = false;
if (this.activateOnInputEvents && this.fittext) {
this.setFontSize(this.getStartFontSizeFromHeight());
this.ngAfterViewInit();
}
}
ngOnInit() {
this.done = false;
if (this.useMaxFontSize) {
this.maxFontSize = parseInt(this.getComputetStyle().fontSize, null);
}
if (this.fittext) {
this.setFontSize(this.maxFontSize);
}
this.el.nativeElement.style.setProperty('will-change', 'content');
}
ngAfterViewInit() {
if (this.isVisible() && this.done === false) {
if (this.fittext) {
const overflow = this.container ? this.checkOverflow(this.container, this.el.nativeElement)
: this.checkOverflow(this.el.nativeElement.parentElement, this.el.nativeElement);
if (overflow) {
if (this.fontSize > this.minFontSize) {
// iterate only until font size is bigger than minimal value
this.setFontSize(this.calculateFontSize(this.fontSize, this.speed));
this.ngAfterViewInit();
}
} else {
if (this.useMaxFontSize) {
if (this.fontSize > this.maxFontSize) {
this.maxFontSize = parseInt(this.getComputetStyle().fontSize, null);
this.setFontSize(this.maxFontSize);
}
}
this.done = true;
}
}
}
}
ngOnChanges(changes: any): void {
if (changes.modelToWatch) {
// change of model to watch - call ngAfterViewInit where is implemented logic to change size
setTimeout(_ => this.ngAfterViewInit() );
}
}
ngAfterViewChecked() {
if (this.fontSize > this.minFontSize) {
this.setFontSize(this.getStartFontSizeFromHeight());
this.ngAfterViewInit();
}
}
private getComputetStyle(): CSSStyleDeclaration {
return window.getComputedStyle(this.container ? this.container : this.el.nativeElement.parentElement);
}
private getStartFontSizeFromHeight(): number {
return this.container ? this.container.clientHeight : this.el.nativeElement.parentElement.clientHeight;
}
private getStartFontSizeFromWeight(): number {
return this.container ? this.container.clientWidth : this.el.nativeElement.parentElement.clientWidth;
}
private isVisible(): boolean {
return this.getStartFontSizeFromHeight() > 0;
}
}

1
src/index.ts Normal file
View file

@ -0,0 +1 @@
export * from './ng2-fittext.module';

23
src/ng2-fittext.module.ts Normal file
View file

@ -0,0 +1,23 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { Ng2FittextDirective } from './directives/ng2-fittext.directive';
@NgModule({
declarations: [
Ng2FittextDirective
],
exports: [
Ng2FittextDirective
],
imports: [
CommonModule
]
})
export class Ng2FittextModule {
static forRoot() {
return {
ngModule: Ng2FittextModule,
providers: []
};
}
}

View file

@ -1,8 +0,0 @@
import { FittextDirective } from './fittext.directive';
describe('FittextDirective', () => {
it('should create an instance', () => {
const directive = new FittextDirective();
expect(directive).toBeTruthy();
});
});

View file

@ -1,134 +0,0 @@
import {Directive, ElementRef, Renderer, Input, AfterViewInit, AfterViewChecked, HostListener, OnInit, OnChanges, SimpleChanges} from '@angular/core';
@Directive({
selector: '[fittext]'
})
export class Ng2FittextDirective implements AfterViewInit, OnInit, OnChanges, AfterViewChecked {
@Input('fittext') fittext: any;
@Input('activateOnResize') activateOnResize: boolean;
@Input('container') container: any;
@Input('activateOnInputEvents') activateOnInputEvents: boolean;
@Input('useMaxFontSize') useMaxFontSize: boolean;
@Input('minFontSize') minFontSize = 7;
@Input('modelToWatch') modelToWatch: any;
private maxFontSize: number = 1000;
private fontSize: number = 1000;
private speed: number = 1.05;
private done: boolean = false;
constructor(public el: ElementRef, public renderer: Renderer) { }
setFontSize(fontSize) {
if (this.isVisible() && this.done === false) {
if (fontSize < this.minFontSize) {
// force that font size will never be lower than minimal allowed font size
fontSize = this.minFontSize;
}
this.fontSize = fontSize;
return this.el.nativeElement.style.setProperty('font-size', (fontSize).toString() + 'px');
}
}
calculateFontSize(fontSize, speed) {
// TODO Do with Gauss
return Math.floor(fontSize / speed);
}
checkOverflow(parent: any, children: any) {
let overflowX = children.scrollWidth - parent.clientWidth;
let overflowY = children.clientHeight - parent.clientHeight;
return (overflowX > 1 || overflowY > 1);
}
@HostListener('window:resize', ['$event'])
onResize() {
this.done = false;
if (this.activateOnResize && this.fittext) {
if (this.activateOnInputEvents && this.fittext) {
this.setFontSize(this.getStartFontSizeFromHeight());
} else {
this.setFontSize(this.getStartFontSizeFromWeight());
}
this.ngAfterViewInit();
}
}
@HostListener('input', ['$event'])
onInputEvents() {
this.done = false;
if (this.activateOnInputEvents && this.fittext) {
this.setFontSize(this.getStartFontSizeFromHeight());
this.ngAfterViewInit();
}
}
ngOnInit() {
this.done = false;
if (this.useMaxFontSize) {
this.maxFontSize = parseInt(this.getComputetStyle().fontSize, null);
}
if (this.fittext) {
this.setFontSize(this.maxFontSize);
}
this.el.nativeElement.style.setProperty('will-change', 'content');
}
ngAfterViewInit() {
if (this.isVisible() && this.done === false) {
if (this.fittext) {
let overflow = this.container ? this.checkOverflow(this.container, this.el.nativeElement)
: this.checkOverflow(this.el.nativeElement.parentElement, this.el.nativeElement);
if (overflow) {
if (this.fontSize > this.minFontSize) {
// iterate only until font size is bigger than minimal value
this.setFontSize(this.calculateFontSize(this.fontSize, this.speed));
this.ngAfterViewInit();
}
} else {
if (this.useMaxFontSize) {
if (this.fontSize > this.maxFontSize) {
this.maxFontSize = parseInt(this.getComputetStyle().fontSize, null);
this.setFontSize(this.maxFontSize);
}
}
this.done = true;
}
}
}
}
ngOnChanges(changes: any): void {
if (changes.modelToWatch) {
// change of model to watch - call ngAfterViewInit where is implemented logic to change size
setTimeout(_ => this.ngAfterViewInit() );
}
}
ngAfterViewChecked() {
if (this.fontSize > this.minFontSize) {
this.setFontSize(this.getStartFontSizeFromHeight());
this.ngAfterViewInit();
}
}
private getComputetStyle(): CSSStyleDeclaration {
return window.getComputedStyle(this.container ? this.container : this.el.nativeElement.parentElement);
}
private getStartFontSizeFromHeight(): number {
return this.container ? this.container.clientHeight : this.el.nativeElement.parentElement.clientHeight;
}
private getStartFontSizeFromWeight(): number {
return this.container ? this.container.clientWidth : this.el.nativeElement.parentElement.clientWidth;
}
private isVisible(): boolean {
return this.getStartFontSizeFromHeight() > 0;
}
}

View file

@ -1,11 +0,0 @@
import { NgModule } from '@angular/core';
import { Ng2FittextDirective } from "./ng2fittext.directive";
@NgModule({
declarations: [
Ng2FittextDirective
],
exports: [Ng2FittextDirective]
})
export class Ng2FittextModule {};

24
src/test.js Normal file
View file

@ -0,0 +1,24 @@
require('core-js/es6');
require('core-js/es7');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
require('zone.js/dist/sync-test');
require('zone.js/dist/proxy');
require('zone.js/dist/jasmine-patch');
const browserTesting = require('@angular/platform-browser-dynamic/testing');
const coreTesting = require('@angular/core/testing');
const context = require.context('./', true, /\.spec\.ts$/);
Error.stackTraceLimit = Infinity;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 2000;
coreTesting.TestBed.resetTestEnvironment();
coreTesting.TestBed.initTestEnvironment(
browserTesting.BrowserDynamicTestingModule,
browserTesting.platformBrowserDynamicTesting()
);
context.keys().forEach(context);

19
src/vendor.ts Normal file
View file

@ -0,0 +1,19 @@
// polyfills Angular 2 requires to be loaded BEFORE the application
// only used in library development--not packaged
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';

69
tasks/build.js Normal file
View file

@ -0,0 +1,69 @@
'use strict';
const fs = require('fs-extra');
const ngc = require('@angular/compiler-cli/src/main').main;
const librarianUtils = require('angular-librarian/commands/utilities');
const path = require('path');
const copyGlobs = require('./copy-globs');
const copyToBuild = require('./copy-build');
const inlineResources = require('./inline-resources');
const rollup = require('./rollup');
const colorize = librarianUtils.colorize;
const rootDir = path.resolve(__dirname, '..');
const buildDir = path.resolve(rootDir, 'build');
const distDir = path.resolve(rootDir, 'dist');
const libName = require(path.resolve(rootDir, 'package.json')).name;
const srcDir = path.resolve(rootDir, 'src');
const tscDir = path.resolve(rootDir, 'out-tsc');
const es5Dir = path.resolve(tscDir, 'lib-es5');
const es2015Dir = path.resolve(tscDir, 'lib-es2015');
const runPromise = (message, fn) => {
return function() {
console.info(colorize.colorize(message, 'cyan'));
return fn().then(complete);
};
};
const complete = (depth = 0) => {
const spaces = ' '.repeat(depth);
console.info(colorize.colorize(`${ spaces }> Complete`, 'green'));
};
const compileCode = () => Promise.all([2015, 5].map((type) =>
ngc({ project: path.resolve(rootDir, `tsconfig.es${ type }.json`)})
.then((exitCode) =>
exitCode === 0 ? Promise.resolve() : Promise.reject()
)
));
const copyMetadata = () =>
copyGlobs(['**/*.d.ts', '**/*.metadata.json'], es2015Dir, distDir);
const copyPackageFiles = () =>
copyGlobs(['.npmignore', 'package.json', 'README.md'], rootDir, distDir)
.then(() => {
const contents = fs.readFileSync(path.resolve(distDir, 'package.json'), 'utf8');
return fs.writeFileSync(path.resolve(distDir, 'package.json'), contents.replace('"dependencies":', '"peerDependencies":'));
});
const copySource = () => copyGlobs('**/*', srcDir, buildDir);
const doInlining = () => inlineResources(buildDir, 'src');
const rollupBundles = () => rollup(libName, {
dist: distDir,
es2015: es2015Dir,
es5: es5Dir,
root: rootDir
});
return Promise.resolve()
.then(runPromise('Copying `src` files into `build`', copySource))
.then(runPromise('Inlining resources', doInlining))
.then(runPromise('Compiling code', compileCode))
.then(runPromise('Copying typings + metadata to `dist`', copyMetadata))
.then(runPromise('Generating bundles via rollup', rollupBundles))
.then(runPromise('Copying package files to `dist`', copyPackageFiles))
.catch((error) => {
console.error('\x1b[31m%s\x1b[0m', '> Build failed\n');
console.error(error);
process.exit(1);
});

16
tasks/copy-build.js Normal file
View file

@ -0,0 +1,16 @@
'use strict';
const fs = require('fs-extra');
// copy all src files -> build
const copyToBuild = (buildDir, sourceDir) => {
fs.ensureDirSync(buildDir);
fs.emptyDirSync(buildDir);
fs.copySync(sourceDir, buildDir);
};
module.exports = copyToBuild;
if (!module.parent) {
copyToBuild('./build', './src');
}

35
tasks/copy-globs.js Normal file
View file

@ -0,0 +1,35 @@
'use strict';
const fs = require('fs-extra');
const glob = require('glob');
const path = require('path');
const copy = (globs, from, to) => {
if (typeof globs === 'string') {
globs = [globs];
}
fs.ensureDir(to);
return Promise.all(
globs.map((fileGlob) => copyGlob(fileGlob, from, to))
);
};
const copyGlob = (fileGlob, from, to) => new Promise((resolve, reject) => {
glob(fileGlob, { cwd: from, nodir: true }, (error, files) => {
if (error) reject(error);
files.forEach((file) => {
const origin = path.resolve(from, file);
const destination = path.resolve(to, file);
const contents = fs.readFileSync(origin, 'utf8');
fs.ensureDirSync(path.dirname(destination));
fs.writeFileSync(destination, contents);
});
resolve();
});
});
module.exports = copy;

186
tasks/inline-resources.js Normal file
View file

@ -0,0 +1,186 @@
'use strict';
// original code by the Angular Material 2 team
const fs = require('fs');
const glob = require('glob');
const path = require('path');
const sass = require('node-sass');
const inlineResources = (globs, sourcePrefix) => {
if (typeof globs === 'string') {
globs = [globs];
}
return Promise.all(
globs.map((pattern) => replaceSource(pattern, sourcePrefix))
);
};
const replaceSource = (pattern, sourcePrefix) => {
// pattern is a directory
if (pattern.indexOf('*') === -1) {
pattern = path.join(pattern, '**', '*');
}
return new Promise((resolve, reject) => {
glob(pattern, {}, (error, files) => {
if (error) reject(Error);
files.filter((name) => /\.ts$/.test(name)).forEach((filePath) => {
try {
inlineFileResources(filePath, sourcePrefix);
} catch (readError) {
reject(readError);
}
});
resolve();
});
});
};
const inlineFileResources = (filePath, sourcePrefix) => {
const content = fs.readFileSync(filePath, 'utf8');
const inlineContents = inlineResourcesFromString(content, sourcePrefix, (url) =>
path.join(path.dirname(filePath), url)
);
fs.writeFileSync(filePath, inlineContents);
};
const inlineResourcesFromString = (content, sourcePrefix, callback) => [
inlineTemplate, inlineStyle, removeModuleId
].reduce((final, method) => method(final, sourcePrefix, callback), content);
const inlineTemplate = (content, sourcePrefix, callback) =>
content.replace(/templateUrl:\s*'([^']+?\.html)'/g, (match, url) => {
const mini = getMiniContents(url, sourcePrefix, callback);
return `template: "${mini}"`;
});
const inlineStyle = (content, sourcePrefix, callback) =>
content.replace(/styleUrls:\s*(\[[\s\S]*?\])/gm, (match, styleUrls) => {
const urls = eval(styleUrls); // string -> array
return 'styles: [' + urls.map((url) => {
const mini = getMiniContents(url, sourcePrefix, callback);
return `"${mini}"`;
}).join(',\n') + ']';
});
const getMiniContents = (url, sourcePrefix, callback) => {
const srcFile = callback(url);
const file = srcFile.replace(/^dist/, sourcePrefix)
const srcDir = file.slice(0, file.lastIndexOf(path.sep));
let template = '';
if (file.match(/\.s(a|c)ss$/)) {
// convert SASS -> CSS
template = sass.renderSync({
file,
importer: (url) => handleSassImport(url, srcDir)
});
template = template.css.toString();
} else {
template = fs.readFileSync(file, 'utf8');
}
return minifyText(template);
};
const handleSassImport = (url, srcDir) => {
const fullUrl = getFullSassUrl(url, srcDir);
let isPartial = false;
let validUrls = getSassUrls(fullUrl);
// if we can't find the file, try to
// see find it as a partial (underscore-prefixed)
if (validUrls.length === 0) {
validUrls = getSassUrls(fullUrl, true);
isPartial = true;
}
const file = getSassImportUrl(validUrls);
// CSS files don't get compiled in
return /\.css$/.test(file) ?
{ contents: fs.readFileSync(file, 'utf8') } :
{ file };
};
const getSassUrls = (url, partial) => {
let extensions = ['sass', 'scss'];
if (!partial) {
extensions = extensions.concat('', 'css');
} else {
const lastSlash = url.lastIndexOf(path.sep);
const urlDir = url.slice(0, lastSlash);
const fileName = url.slice(lastSlash + 1);
if (fileName[0] !== '_') {
url = urlDir + path.sep + '_' + fileName;
}
}
return extensions.reduce((valid, extension) => {
const extensionUrl = verifyUrl(url, extension);
if (extensionUrl) {
valid = valid.concat(extensionUrl);
}
return valid;
}, []);
};
const verifyUrl = (url, extension) => {
if (extension) {
url = url + `.${ extension }`;
}
if (!fs.existsSync(url)) {
url = null;
}
return url;
}
// convert ~-prefixed filenames to node_modules-prefixed
// make all others relative to srcDir
const getFullSassUrl = (url, srcDir) =>
/^~/.test(url) ?
path.resolve('node_modules', url.slice(1)) :
path.resolve(srcDir, url);
const getSassImportUrl = (validUrls) => {
if (validUrls.length !== 1) {
let error = 'Cannot determine Sass/CSS file to process. ';
if (validUrls.length === 0) {
error = error + `\n There are no files matching ${ url }`;
} else {
error = error + 'Candidates:\n ' + validUrls.join('\n ')
+ '\nPlease delete or rename all but one of these files or specify the extension to use.';
}
throw new Error(error);
}
return validUrls[0];
};
const minifyText = (text) => text
.replace(/([\n\r]\s*)+/gm, ' ')
.replace(/"/g, '\\"');
const removeModuleId = (content) =>
content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
module.exports = inlineResources;
if (!module.parent) {
inlineResources('./build', 'src');
}

134
tasks/rollup.js Normal file
View file

@ -0,0 +1,134 @@
'use strict';
const erectorUtils = require('erector-set/src/utils');
const fs = require('fs-extra');
const librarianUtils = require('angular-librarian/commands/utilities');
const path = require('path');
const rollup = require('rollup');
const rollupCommon = require('rollup-plugin-commonjs');
const rollupNodeResolve = require('rollup-plugin-node-resolve');
const rollupSourcemaps = require('rollup-plugin-sourcemaps');
const rollupUglify = require('rollup-plugin-uglify');
const doRollup = (libName, dirs) => {
const nameParts = extractName(libName);
const es5Entry = path.resolve(dirs.es5, `${ nameParts.package }.js`);
const es2015Entry = path.resolve(dirs.es2015, `${ nameParts.package }.js`);
const destinations = generateDestinations(dirs.dist, nameParts);
const baseConfig = generateConfig({
entry: es5Entry,
external: [
'@angular/common',
'@angular/core'
],
globals: {
'@angular/common': 'ng.common',
'@angular/core': 'ng.core'
},
moduleName: librarianUtils.caseConvert.dashToCamel(nameParts.package),
onwarn: function rollupOnWarn(warning) {
// keeps TypeScript this errors down
if (warning.code !== 'THIS_IS_UNDEFINED') {
console.warn(warning.message);
}
},
plugins: [
rollupNodeResolve({
jsnext: true,
module: true
}),
rollupSourcemaps()
],
sourceMap: true
}, dirs.root);
const fesm2015Config = Object.assign({}, baseConfig, {
entry: es2015Entry,
dest: destinations.fesm2015,
format: 'es'
});
const fesm5Config = Object.assign({}, baseConfig, {
dest: destinations.fesm5,
format: 'es'
});
const minUmdConfig = Object.assign({}, baseConfig, {
dest: destinations.minUmd,
format: 'umd',
plugins: baseConfig.plugins.concat([rollupUglify({})])
});
const umdConfig = Object.assign({}, baseConfig, {
dest: destinations.umd,
format: 'umd'
});
const bundles = [
fesm2015Config,
fesm5Config,
minUmdConfig,
umdConfig
].map((config) =>
rollup.rollup(config).then((bundle) =>
bundle.write(config)
)
);
return Promise.all(bundles);
};
const extractName = (libName) => {
const isScoped = librarianUtils.checkIsScopedName(libName);
const nameParts = {
package: libName,
scope: undefined
};
if (isScoped) {
const parts = libName.split('/', 2);
nameParts.package = parts[1];
nameParts.scope = parts[0];
}
return nameParts;
};
const generateDestinations = (dist, nameParts) => {
const bundleDest = path.resolve(dist, 'bundles');
let fesmDest = path.resolve(dist);
if (nameParts.scope) {
fesmDest = path.resolve(fesmDest, nameParts.scope);
fs.ensureDirSync(fesmDest);
}
return Object.freeze({
fesm2015: path.resolve(fesmDest,`${ nameParts.package }.js`),
fesm5: path.resolve(fesmDest,`${ nameParts.package }.es5.js`),
minUmd: path.resolve(bundleDest, `${ nameParts.package }.umd.min.js`),
umd: path.resolve(bundleDest, `${ nameParts.package }.umd.js`)
});
};
const generateConfig = (base, rootDir) => {
let commonjsIncludes = ['node_modules/rxjs/**'];
const customLocation = path.resolve(rootDir, 'configs', 'rollup.config.js');
if (fs.existsSync(customLocation)) {
const custom = require(customLocation);
const external = (custom.external || []).filter((external) => base.external.indexOf(external) === -1);
const includes = (custom.commonjs || []).filter((include) => commonjsIncludes.indexOf(include) === -1);
base.external = base.external.concat(external);
base.globals = erectorUtils.mergeDeep(custom.globals, base.globals);
commonjsIncludes = commonjsIncludes.concat(includes);
}
base.plugins.unshift(
rollupCommon({
include: commonjsIncludes
})
);
return base;
};
module.exports = doRollup;

66
tasks/test.js Normal file
View file

@ -0,0 +1,66 @@
'use strict';
const fs = require('fs');
const path = require('path');
const Server = require('karma').Server;
function run(type) {
const config = getConfig(type);
const server = new Server(config, function(exitCode) {
process.exit(exitCode);
});
server.start();
}
function getConfig(type) {
switch (type) {
case 'headless':
case 'hl':
case 'h':
return getHeadlessConfig();
case 'all':
case 'a':
return getAllConfig();
case 'watch':
case 'w':
return getWatchConfig();
default:
return getSingleConfig();
}
}
function getSingleConfig() {
let config = getHeadlessConfig();
config.singleRun = true;
return config;
}
function getHeadlessConfig() {
let config = getAllConfig();
config.browsers = ['PhantomJS'];
return config;
}
function getWatchConfig() {
let config = getAllConfig(true);
config.browsers = ['Chrome'];
return config;
}
const getAllConfig = (watch) => ({
configFile: path.resolve(__dirname, '..', 'karma.conf.js'),
webpack: require(path.resolve(__dirname, '..', 'webpack', 'webpack.test.js'))(watch),
});
module.exports = run;
if (!module.parent) {
run(process.argv[2]);
}

34
tsconfig.es2015.json Normal file
View file

@ -0,0 +1,34 @@
{
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"flatModuleId": "ng2-fittext",
"flatModuleOutFile": "ng2-fittext.js",
"genDir": "../out-tsc/lib-gen-dir/",
"strictMetadataEmit": true,
"skipTemplateCodegen": true
},
"compilerOptions": {
"baseUrl": "",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"module": "es2015",
"moduleResolution": "node",
"outDir": "./out-tsc/lib-es2015/",
"skipLibCheck": true,
"sourceMap": true,
"stripInternal": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es2015",
"typeRoots": [
"./node_modules/@types"
]
},
"files": [
"./build/index.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true
}
}

34
tsconfig.es5.json Normal file
View file

@ -0,0 +1,34 @@
{
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"flatModuleId": "ng2-fittext",
"flatModuleOutFile": "ng2-fittext.js",
"genDir": "../out-tsc/lib-gen-dir/",
"strictMetadataEmit": true,
"skipTemplateCodegen": true
},
"compilerOptions": {
"baseUrl": "",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"module": "es2015",
"moduleResolution": "node",
"outDir": "./out-tsc/lib-es5/",
"skipLibCheck": true,
"sourceMap": true,
"stripInternal": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5",
"typeRoots": [
"./node_modules/@types"
]
},
"files": [
"./build/index.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true
}
}

View file

@ -1,19 +1,28 @@
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"target": "es5",
"sourceMap": true,
"inlineSources": false,
"declaration": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"stripInternal": true,
"skipLibCheck": true
},
"files": [
"ng2fittext.ts",
"ng2fittext.d.ts",
"index.ts"
]
}
"angularCompilerOptions": {
"strictMetadataEmit": true,
"skipTemplateCodegen": true
},
"compilerOptions": {
"baseUrl": "",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"mapRoot": "./",
"module": "es2015",
"moduleResolution": "node",
"outDir": "./dist",
"sourceMap": true,
"target": "es5",
"typeRoots": [
"./node_modules/@types"
]
},
"files": [
"./src/index.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true
}
}

20
tsconfig.test.json Normal file
View file

@ -0,0 +1,20 @@
{
"buildOnSave": false,
"compilerOptions": {
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"module": "commonjs",
"moduleResolution": "node",
"removeComments": false,
"sourceMap": true,
"target": "es5",
"typeRoots": [
"./node_modules/@types"
]
},
"compileOnSave": false,
"files": [
"./src/ng2-fittext.module.ts"
]
}

116
tslint.json Normal file
View file

@ -0,0 +1,116 @@
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"import-blacklist": [true, "rxjs"],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"typeof-compare": true,
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [true, "attribute", "", "camelCase"],
"component-selector": [true, "element", "", "kebab-case"],
"use-input-property-decorator": true,
"use-output-property-decorator": true,
"use-host-property-decorator": true,
"no-input-rename": true,
"no-output-rename": true,
"use-life-cycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-access-missing-member": true,
"templates-use-public": true,
"invoke-injectable": true
}
}

70
webpack/webpack.common.js Normal file
View file

@ -0,0 +1,70 @@
'use strict';
const fs = require('fs');
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const ContextReplacementPlugin = webpack.ContextReplacementPlugin;
const LoaderOptionsPlugin = webpack.LoaderOptionsPlugin;
const webpackUtils = require('./webpack.utils');
const getCommonConfig = (type) => {
const tsconfigType = type !== 'dev' ? `.${ type }` : '';
return {
module: {
rules: [
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
'awesome-typescript-loader?configFileName=' + webpackUtils.rootPath(`tsconfig${ tsconfigType }.json`),
'angular2-template-loader?keepUrl=true'
]
},
{ test: /\.html$/, use: 'raw-loader' },
{
use: ['url-loader?limit=10000'],
test: /\.(woff2?|ttf|eot|svg|jpg|jpeg|json|gif|png)(\?v=\d+\.\d+\.\d+)?$/
}
]
},
performance: { hints: false },
plugins: [
new ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)@angular/,
__dirname
),
new LoaderOptionsPlugin({
debug: true,
options: {
emitErrors: true
}
}),
new ExtractTextPlugin("*.css")
],
resolve: {
extensions: [ '.js', '.ts' ],
modules: [ webpackUtils.rootPath('node_modules') ]
}
};
};
module.exports = (type, typeConfig) => {
const configs = [getCommonConfig(type), typeConfig];
const customConfigPath = webpackUtils.rootPath('configs', `webpack.${ type }.js`);
if (fs.existsSync(customConfigPath)) {
let customConfig = require(customConfigPath);
if (Object.prototype.toString.call(customConfig) === '[object Function]') {
customConfig = customConfig();
}
configs.push(customConfig);
}
return webpackMerge.apply(null, configs);
};

77
webpack/webpack.dev.js Normal file
View file

@ -0,0 +1,77 @@
'use strict';
const HtmlWebpack = require('html-webpack-plugin');
const webpack = require('webpack');
const ChunkWebpack = webpack.optimize.CommonsChunkPlugin;
const webpackCommon = require('./webpack.common');
const webpackUtils = require('./webpack.utils');
const entryPoints = [
'vendor',
'scripts',
'styles',
'app'
];
const examplePath = function examples() {
return webpackUtils.relayArguments(
webpackUtils.rootPath,
'examples',
arguments
);
};
module.exports = webpackCommon('dev', {
devServer: {
contentBase: webpackUtils.rootPath('dist'),
port: 9000
},
devtool: 'cheap-module-eval-source-map',
entry: {
app: [ examplePath('example.main') ],
scripts: [],
vendor: [ webpackUtils.srcPath('vendor') ],
styles: [ examplePath('styles.scss') ]
},
module: {
rules: webpackUtils.buildRules({
cssExtract: examplePath(),
sassLoader: examplePath('styles.scss')
}, {
include: examplePath(),
test: /styles\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
})
},
output: {
filename: '[name].bundle.js',
path: webpackUtils.rootPath('dist')
},
plugins: [
new ChunkWebpack({
filename: 'vendor.bundle.js',
minChunks: Infinity,
name: 'vendor'
}),
new HtmlWebpack({
// shameless/shamefully stolen from Angular CLI
chunksSortMode: function(left, right) {
const leftIndex = entryPoints.indexOf(left.names[0]);
const rightIndex = entryPoints.indexOf(right.names[0]);
let direction = 0;
if (leftIndex > rightIndex) {
direction = 1;
} else if (leftIndex < rightIndex) {
direction = -1;
}
return direction;
},
filename: 'index.html',
inject: 'body',
template: examplePath('index.html')
})
]
});

46
webpack/webpack.test.js Normal file
View file

@ -0,0 +1,46 @@
'use strict';
const webpack = require('webpack');
const SourceMapDevToolPlugin = webpack.SourceMapDevToolPlugin;
const webpackCommon = require('./webpack.common');
const webpackUtils = require('./webpack.utils');
module.exports = (watch) => {
return webpackCommon('test', {
devtool: watch ? 'inline-source-map' : 'cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.s?css$/,
use: ['raw-loader', 'css-loader', 'sass-loader']
},
{
enforce: 'pre',
exclude: /node_modules/,
test: /\.ts$/,
use: 'tslint-loader'
},
{
enforce: 'post',
exclude: [
/node_modules/,
/\.(e2e|spec\.)ts$/
],
test: /\.ts$/,
use: 'istanbul-instrumenter-loader?esModules=true'
}
]
},
plugins: [
new SourceMapDevToolPlugin({
filename: null,
test: /\.ts$/
})
],
resolve: {
modules: [ webpackUtils.srcPath() ],
moduleExtensions: ['-loader']
}
});
};

66
webpack/webpack.utils.js Normal file
View file

@ -0,0 +1,66 @@
'use strict';
const ExtractText = require('extract-text-webpack-plugin');
const path = require('path');
function rootPath() {
const rootDir = path.resolve(__dirname, '..');
return relayArguments(path.resolve, rootDir, arguments);
}
exports.rootPath = rootPath;
function srcPath() {
return relayArguments(rootPath, 'src', arguments);
};
exports.srcPath = srcPath;
function relayArguments(method, prefix, args) {
const fullArguments = [prefix].concat(
Array.prototype.slice.apply(args)
);
return method.apply(null, fullArguments);
}
exports.relayArguments = relayArguments;
exports.buildRules = (excludes, extraRules) => {
let cssExtractExcludes = [srcPath()];
let sassLoaderExcludes = [/node_modules/];
let rules;
excludes = excludes || {};
if (excludes.cssExtract) {
cssExtractExcludes = cssExtractExcludes.concat(excludes.cssExtract);
}
if (excludes.sassLoader) {
sassLoaderExcludes = sassLoaderExcludes.concat(excludes.sassLoader);
}
rules = [
{
exclude: cssExtractExcludes,
test: /\.css$/,
use: ExtractText.extract({
fallback: 'style-loader',
use: 'css-loader?sourceMap'
})
},
{
exclude: /node_modules/,
test: /\.css$/,
use: ['css-to-string-loader', 'css-loader']
},
{
exclude: sassLoaderExcludes,
use: ['css-to-string-loader', 'css-loader', 'sass-loader'],
test: /\.scss$/
}
];
if (extraRules) {
rules = rules.concat(extraRules);
}
return rules;
};