├── .npmignore ├── .npmrc ├── integration-test ├── wcmio-archetype-module │ ├── .nvmrc │ ├── .npmrc │ ├── .gitignore │ ├── expected-result │ │ ├── myproject1.all │ │ │ ├── css.txt │ │ │ ├── js.txt │ │ │ └── .content.xml │ │ └── myproject1.app │ │ │ ├── js.txt │ │ │ ├── css.txt │ │ │ ├── resources │ │ │ └── img │ │ │ │ └── favicon.ico │ │ │ └── .content.xml │ ├── src │ │ ├── index.scss │ │ ├── components │ │ │ ├── image │ │ │ │ └── image.scss │ │ │ └── customcarousel │ │ │ │ ├── customcarousel.js │ │ │ │ └── customcarousel.hbs │ │ ├── index.js │ │ └── index.hbs │ ├── config │ │ ├── webpack │ │ │ ├── base │ │ │ │ ├── setup │ │ │ │ │ ├── index.js │ │ │ │ │ ├── entryConfig.js │ │ │ │ │ └── outputConfig.js │ │ │ │ ├── tasks │ │ │ │ │ ├── index.js │ │ │ │ │ ├── es6.js │ │ │ │ │ ├── html.js │ │ │ │ │ ├── clean.js │ │ │ │ │ ├── handlebars.js │ │ │ │ │ ├── copy.js │ │ │ │ │ └── scss.js │ │ │ │ └── index.js │ │ │ ├── prod │ │ │ │ └── index.js │ │ │ └── dev │ │ │ │ ├── server.js │ │ │ │ └── index.js │ │ └── path.config.js │ ├── public │ │ └── img │ │ │ └── favicon.ico │ ├── .babelrc │ ├── README.md │ ├── webpack.config.babel.js │ ├── clientlib.config.js │ ├── package.json │ ├── compare-results.js │ └── pom.xml ├── wcmio-archetype-commonjs │ ├── .nvmrc │ ├── .npmrc │ ├── .gitignore │ ├── expected-result │ │ ├── myproject1.all │ │ │ ├── js.txt │ │ │ └── css.txt │ │ ├── myproject1.app │ │ │ ├── js.txt │ │ │ ├── css.txt │ │ │ └── resources │ │ │ │ └── img │ │ │ │ └── favicon.ico │ │ ├── myproject1.app.json │ │ └── myproject1.all.json │ ├── src │ │ ├── index.scss │ │ ├── components │ │ │ ├── image │ │ │ │ └── image.scss │ │ │ └── customcarousel │ │ │ │ ├── customcarousel.js │ │ │ │ └── customcarousel.hbs │ │ ├── index.js │ │ └── index.hbs │ ├── config │ │ ├── webpack │ │ │ ├── base │ │ │ │ ├── setup │ │ │ │ │ ├── index.js │ │ │ │ │ ├── entryConfig.js │ │ │ │ │ └── outputConfig.js │ │ │ │ ├── tasks │ │ │ │ │ ├── index.js │ │ │ │ │ ├── es6.js │ │ │ │ │ ├── html.js │ │ │ │ │ ├── clean.js │ │ │ │ │ ├── handlebars.js │ │ │ │ │ ├── copy.js │ │ │ │ │ └── scss.js │ │ │ │ └── index.js │ │ │ ├── prod │ │ │ │ └── index.js │ │ │ └── dev │ │ │ │ ├── server.js │ │ │ │ └── index.js │ │ └── path.config.js │ ├── public │ │ └── img │ │ │ └── favicon.ico │ ├── .babelrc │ ├── README.md │ ├── webpack.config.babel.js │ ├── clientlib.config.js │ ├── package.json │ ├── compare-results.mjs │ └── pom.xml └── wcmio-archetype-module-cjs │ ├── .nvmrc │ ├── .npmrc │ ├── .gitignore │ ├── expected-result │ ├── myproject1.all │ │ ├── css.txt │ │ ├── js.txt │ │ └── .content.xml │ └── myproject1.app │ │ ├── css.txt │ │ ├── js.txt │ │ ├── resources │ │ └── img │ │ │ └── favicon.ico │ │ └── .content.xml │ ├── src │ ├── index.scss │ ├── components │ │ ├── image │ │ │ └── image.scss │ │ └── customcarousel │ │ │ ├── customcarousel.js │ │ │ └── customcarousel.hbs │ ├── index.js │ └── index.hbs │ ├── config │ ├── webpack │ │ ├── base │ │ │ ├── setup │ │ │ │ ├── index.js │ │ │ │ ├── entryConfig.js │ │ │ │ └── outputConfig.js │ │ │ ├── tasks │ │ │ │ ├── index.js │ │ │ │ ├── es6.js │ │ │ │ ├── html.js │ │ │ │ ├── clean.js │ │ │ │ ├── handlebars.js │ │ │ │ ├── copy.js │ │ │ │ └── scss.js │ │ │ └── index.js │ │ ├── prod │ │ │ └── index.js │ │ └── dev │ │ │ ├── server.js │ │ │ └── index.js │ └── path.config.js │ ├── public │ └── img │ │ └── favicon.ico │ ├── .babelrc │ ├── README.md │ ├── webpack.config.babel.js │ ├── clientlib.config.cjs │ ├── package.json │ ├── compare-results.js │ └── pom.xml ├── test ├── src │ └── frontend │ │ ├── css │ │ ├── grid.less │ │ ├── styling.css │ │ └── lib.css │ │ ├── secondapp │ │ ├── main.css │ │ └── js │ │ │ └── lib.js │ │ ├── resources │ │ ├── notice.txt │ │ └── template.html │ │ └── js │ │ ├── app.js │ │ └── libs │ │ ├── mylib.min.js │ │ ├── mylib.js │ │ └── mylib.min.js.map ├── expected │ └── clientlibs-root │ │ ├── test.base.apps.five │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ └── resources │ │ │ └── template.html │ │ ├── redirectOutputTestWithXML │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ ├── resources │ │ │ └── template.html │ │ └── .content.xml │ │ ├── test.base.apps.secondapp │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ └── resources │ │ │ └── template.html │ │ ├── test.base.apps.customProperties │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ ├── resources │ │ │ └── template.html │ │ └── .content.xml │ │ ├── myPrestructuredLibrary │ │ ├── css │ │ │ ├── vendor │ │ │ │ └── main.css │ │ │ └── style │ │ │ │ ├── styling.css │ │ │ │ └── lib.css │ │ ├── js.txt │ │ ├── css.txt │ │ └── js │ │ │ ├── app.js │ │ │ └── libs │ │ │ ├── mylib.min.js │ │ │ ├── mylib.js │ │ │ └── mylib.min.js.map │ │ ├── test.base.apps.fourth │ │ ├── css │ │ │ ├── vendor │ │ │ │ └── main.css │ │ │ └── style │ │ │ │ ├── styling.css │ │ │ │ └── lib.css │ │ ├── js.txt │ │ ├── css.txt │ │ └── js │ │ │ ├── app.js │ │ │ └── libs │ │ │ ├── mylib.min.js │ │ │ ├── mylib.js │ │ │ └── mylib.min.js.map │ │ ├── test.base.apps.mainapp │ │ ├── css.txt │ │ ├── css │ │ │ ├── styling.css │ │ │ └── lib.css │ │ ├── js.txt │ │ └── js │ │ │ ├── app.js │ │ │ └── libs │ │ │ ├── mylib.min.js │ │ │ └── mylib.min.js.map │ │ ├── test.base.apps.customPropertiesNotAllowed │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ ├── resources │ │ │ └── template.html │ │ └── .content.xml │ │ ├── test.base.apps.ignoreOption │ │ ├── js.txt │ │ └── js │ │ │ ├── app.js │ │ │ └── libs │ │ │ └── mylib.js │ │ ├── test.base.apps.serializationFormatXML │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ ├── resources │ │ │ └── template.html │ │ └── .content.xml │ │ ├── test.base.apps.withLessFiles │ │ ├── css │ │ │ ├── grid.less │ │ │ ├── styling.css │ │ │ └── lib.css │ │ └── css.txt │ │ ├── test.base.apps.serializationFormatSlingXML │ │ ├── css.txt │ │ ├── js.txt │ │ ├── style │ │ │ └── main.css │ │ ├── js │ │ │ └── secondapp-lib.js │ │ └── resources │ │ │ └── template.html │ │ ├── test.base.apps.thirdapp │ │ └── notice.txt │ │ ├── test.base.apps.fourth.json │ │ ├── test.base.apps.thirdapp.json │ │ ├── test.base.apps.fourthWithOutputPath.json │ │ ├── test.base.apps.secondapp.json │ │ ├── test.base.apps.five.json │ │ ├── test.base.apps.mainapp.json │ │ └── test.base.apps.serializationFormatSlingXML.xml ├── TestCase.test.js └── clientlib.config.js ├── .gitignore ├── .github ├── release-drafter.yml ├── workflows │ ├── release-drafter.yml │ ├── build.yml │ ├── release.yml │ └── integration-tests.yml └── renovate.json ├── .gitattributes ├── package.json ├── bin └── clientlib-cli.js ├── LICENSE ├── README.md └── lib └── clientlib.js /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm*.log 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/.nvmrc: -------------------------------------------------------------------------------- 1 | 24.11.0 -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/.nvmrc: -------------------------------------------------------------------------------- 1 | 24.11.0 -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/.nvmrc: -------------------------------------------------------------------------------- 1 | 24.11.0 -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true -------------------------------------------------------------------------------- /test/src/frontend/css/grid.less: -------------------------------------------------------------------------------- 1 | .grid { 2 | display: flex; 3 | } -------------------------------------------------------------------------------- /test/src/frontend/css/styling.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/src/frontend/secondapp/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | result/ 3 | node/ -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | result/ 3 | node/ -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | result/ 3 | node/ -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.all/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.all/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.all/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/src/frontend/css/lib.css: -------------------------------------------------------------------------------- 1 | /* lib styles here */ 2 | 3 | .lib { 4 | font-size: 30px; 5 | } -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.all/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.app/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.all/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.all/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.app/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/css/vendor/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/css/vendor/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | styling.css 4 | lib.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/css/styling.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/src/frontend/resources/notice.txt: -------------------------------------------------------------------------------- 1 | This is a txt file and the content does not make any sense... -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.app/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | app.css -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.app/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | app.css -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.app/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.app/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | app.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/css/style/styling.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/css/style/styling.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.ignoreOption/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js 4 | libs/mylib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js 4 | libs/mylib.min.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.withLessFiles/css/grid.less: -------------------------------------------------------------------------------- 1 | .grid { 2 | display: flex; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.withLessFiles/css/styling.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/src/frontend/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML/css.txt: -------------------------------------------------------------------------------- 1 | #base=style 2 | 3 | main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | secondapp-lib.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML/style/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #000; 3 | } -------------------------------------------------------------------------------- /test/src/frontend/secondapp/js/lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js 4 | libs/mylib.js 5 | libs/mylib.min.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/js.txt: -------------------------------------------------------------------------------- 1 | #base=js 2 | 3 | app.js 4 | libs/mylib.js 5 | libs/mylib.min.js -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.withLessFiles/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | grid.less 4 | styling.css 5 | lib.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.thirdapp/notice.txt: -------------------------------------------------------------------------------- 1 | This is a txt file and the content does not make any sense... -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | style/lib.css 4 | style/styling.css 5 | vendor/main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/css/lib.css: -------------------------------------------------------------------------------- 1 | /* lib styles here */ 2 | 3 | .lib { 4 | font-size: 30px; 5 | } -------------------------------------------------------------------------------- /test/src/frontend/js/libs/mylib.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var MyLib=function(){this.test="MyLib"}; 2 | //# sourceMappingURL=mylib.min.js.map -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/index.scss: -------------------------------------------------------------------------------- 1 | // Externals 2 | @import "~bootstrap/scss/bootstrap"; 3 | 4 | // Components 5 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/index.scss: -------------------------------------------------------------------------------- 1 | // Externals 2 | @import "~bootstrap/scss/bootstrap"; 3 | 4 | // Components 5 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/css.txt: -------------------------------------------------------------------------------- 1 | #base=css 2 | 3 | style/lib.css 4 | style/styling.css 5 | vendor/main.css -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/css/style/lib.css: -------------------------------------------------------------------------------- 1 | /* lib styles here */ 2 | 3 | .lib { 4 | font-size: 30px; 5 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/css/style/lib.css: -------------------------------------------------------------------------------- 1 | /* lib styles here */ 2 | 3 | .lib { 4 | font-size: 30px; 5 | } -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.withLessFiles/css/lib.css: -------------------------------------------------------------------------------- 1 | /* lib styles here */ 2 | 3 | .lib { 4 | font-size: 30px; 5 | } -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/index.scss: -------------------------------------------------------------------------------- 1 | // Externals 2 | @import "~bootstrap/scss/bootstrap"; 3 | 4 | // Components 5 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.ignoreOption/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/setup/index.js: -------------------------------------------------------------------------------- 1 | export * from "./entryConfig.js"; 2 | export * from "./outputConfig.js"; 3 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/setup/index.js: -------------------------------------------------------------------------------- 1 | export * from "./entryConfig.js"; 2 | export * from "./outputConfig.js"; 3 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/src/frontend/js/libs/mylib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var MyLib = function() { 4 | this.test = "MyLib"; 5 | }; 6 | //# sourceMappingURL=mylib.js.map -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/setup/index.js: -------------------------------------------------------------------------------- 1 | export * from "./entryConfig.js"; 2 | export * from "./outputConfig.js"; 3 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/js/libs/mylib.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var MyLib=function(){this.test="MyLib"}; 2 | //# sourceMappingURL=mylib.min.js.map -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/js/libs/mylib.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var MyLib=function(){this.test="MyLib"}; 2 | //# sourceMappingURL=mylib.min.js.map -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/js/libs/mylib.min.js: -------------------------------------------------------------------------------- 1 | "use strict";var MyLib=function(){this.test="MyLib"}; 2 | //# sourceMappingURL=mylib.min.js.map -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML/js/secondapp-lib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var Test = function() { 4 | this.test = "test"; 5 | }; -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/prod/index.js: -------------------------------------------------------------------------------- 1 | export const prodConfig = { 2 | devtool: "source-map", 3 | stats: "errors-only", 4 | bail: true 5 | }; 6 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/prod/index.js: -------------------------------------------------------------------------------- 1 | export const prodConfig = { 2 | devtool: "source-map", 3 | stats: "errors-only", 4 | bail: true 5 | }; 6 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "categories": [ 4 | "test.base.apps.fourth" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/src/frontend/js/libs/mylib.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["mylib.js"],"names":["MyLib","this","test"],"mappings":"AACA,YACA,IAAIA,OAAQ,WACVC,KAAKC,KAAO","file":"mylib.min.js"} -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/prod/index.js: -------------------------------------------------------------------------------- 1 | export const prodConfig = { 2 | devtool: "source-map", 3 | stats: "errors-only", 4 | bail: true 5 | }; 6 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/js/libs/mylib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var MyLib = function() { 4 | this.test = "MyLib"; 5 | }; 6 | //# sourceMappingURL=mylib.js.map -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/js/libs/mylib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var MyLib = function() { 4 | this.test = "MyLib"; 5 | }; 6 | //# sourceMappingURL=mylib.js.map -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.thirdapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "categories": [ 4 | "test.base.apps.thirdapp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.ignoreOption/js/libs/mylib.js: -------------------------------------------------------------------------------- 1 | 2 | "use strict"; 3 | var MyLib = function() { 4 | this.test = "MyLib"; 5 | }; 6 | //# sourceMappingURL=mylib.js.map -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm*.log 3 | tmp 4 | .idea 5 | .DS_Store 6 | .project 7 | .sublime-* 8 | .project 9 | .settings 10 | 11 | # ignore result folder from mocha test 12 | result/ -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-commonjs/public/img/favicon.ico -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-module/public/img/favicon.ico -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/dev/server.js: -------------------------------------------------------------------------------- 1 | export const devServer = { 2 | devServer: { 3 | compress: true, 4 | port: 9000, 5 | static: "./public" 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/dev/server.js: -------------------------------------------------------------------------------- 1 | export const devServer = { 2 | devServer: { 3 | compress: true, 4 | port: 9000, 5 | static: "./public" 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-module-cjs/public/img/favicon.ico -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/dev/server.js: -------------------------------------------------------------------------------- 1 | export const devServer = { 2 | devServer: { 3 | compress: true, 4 | port: 9000, 5 | static: "./public" 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourthWithOutputPath.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "categories": [ 4 | "test.base.apps.fourthWithOutputPath" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/myPrestructuredLibrary/js/libs/mylib.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["mylib.js"],"names":["MyLib","this","test"],"mappings":"AACA,YACA,IAAIA,OAAQ,WACVC,KAAKC,KAAO","file":"mylib.min.js"} -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.fourth/js/libs/mylib.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["mylib.js"],"names":["MyLib","this","test"],"mappings":"AACA,YACA,IAAIA,OAAQ,WACVC,KAAKC,KAAO","file":"mylib.min.js"} -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp/js/libs/mylib.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["mylib.js"],"names":["MyLib","this","test"],"mappings":"AACA,YACA,IAAIA,OAAQ,WACVC,KAAKC,KAAO","file":"mylib.min.js"} -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "allowProxy": true, 4 | "categories": [ 5 | "myproject1.app" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/setup/entryConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const entry = { 4 | app: [path.resolve("src/index.js"), path.resolve("src/index.scss")] 5 | }; 6 | -------------------------------------------------------------------------------- /test/src/frontend/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/setup/entryConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const entry = { 4 | app: [path.resolve("src/index.js"), path.resolve("src/index.scss")] 5 | }; 6 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/setup/entryConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const entry = { 4 | app: [path.resolve("src/index.js"), path.resolve("src/index.scss")] 5 | }; 6 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/components/image/image.scss: -------------------------------------------------------------------------------- 1 | .cmp-image img { 2 | max-width: 100%; 3 | height: auto; 4 | } 5 | 6 | .cmp-image .cmp-image__title { 7 | display: block; 8 | margin: .75rem 0; 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/components/image/image.scss: -------------------------------------------------------------------------------- 1 | .cmp-image img { 2 | max-width: 100%; 3 | height: auto; 4 | } 5 | 6 | .cmp-image .cmp-image__title { 7 | display: block; 8 | margin: .75rem 0; 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/components/image/image.scss: -------------------------------------------------------------------------------- 1 | .cmp-image img { 2 | max-width: 100%; 3 | height: auto; 4 | } 5 | 6 | .cmp-image .cmp-image__title { 7 | display: block; 8 | margin: .75rem 0; 9 | } 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/index.js: -------------------------------------------------------------------------------- 1 | import CustomCarousel from "./components/customcarousel/customcarousel.js"; 2 | 3 | // Document Ready 4 | document.addEventListener('DOMContentLoaded', () => { 5 | CustomCarousel(); 6 | }); 7 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/index.js: -------------------------------------------------------------------------------- 1 | import CustomCarousel from "./components/customcarousel/customcarousel.js"; 2 | 3 | // Document Ready 4 | document.addEventListener('DOMContentLoaded', () => { 5 | CustomCarousel(); 6 | }); 7 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/index.js: -------------------------------------------------------------------------------- 1 | import CustomCarousel from "./components/customcarousel/customcarousel.js"; 2 | 3 | // Document Ready 4 | document.addEventListener('DOMContentLoaded', () => { 5 | CustomCarousel(); 6 | }); 7 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'Next Release' 2 | tag-template: 'next' 3 | 4 | exclude-labels: 5 | - integration-test 6 | exclude-contributors: 7 | - renovate 8 | 9 | template: | 10 | ## What’s Changed 11 | 12 | $CHANGES 13 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/dev/index.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | import { devServer } from "./server.js"; 3 | 4 | export const devConfig = merge(devServer, { 5 | devtool: "source-map", 6 | bail: true 7 | }); 8 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/index.js: -------------------------------------------------------------------------------- 1 | export * from "./es6.js"; 2 | export * from "./handlebars.js"; 3 | export * from "./scss.js"; 4 | export * from "./html.js"; 5 | export * from "./clean.js"; 6 | export * from "./copy.js"; 7 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/dev/index.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | import { devServer } from "./server.js"; 3 | 4 | export const devConfig = merge(devServer, { 5 | devtool: "source-map", 6 | bail: true 7 | }); 8 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/dev/index.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | import { devServer } from "./server.js"; 3 | 4 | export const devConfig = merge(devServer, { 5 | devtool: "source-map", 6 | bail: true 7 | }); 8 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/index.js: -------------------------------------------------------------------------------- 1 | export * from "./es6.js"; 2 | export * from "./handlebars.js"; 3 | export * from "./scss.js"; 4 | export * from "./html.js"; 5 | export * from "./clean.js"; 6 | export * from "./copy.js"; 7 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.app/resources/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-module/expected-result/myproject1.app/resources/img/favicon.ico -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.app/resources/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-commonjs/expected-result/myproject1.app/resources/img/favicon.ico -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/index.js: -------------------------------------------------------------------------------- 1 | export * from "./es6.js"; 2 | export * from "./handlebars.js"; 3 | export * from "./scss.js"; 4 | export * from "./html.js"; 5 | export * from "./clean.js"; 6 | export * from "./copy.js"; 7 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.app/resources/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wcm-io-frontend/aem-clientlib-generator/HEAD/integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.app/resources/img/favicon.ico -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML/resources/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

Test file

9 | 10 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/es6.js: -------------------------------------------------------------------------------- 1 | export const es6 = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.js$/, 6 | exclude: /node_modules/, 7 | loader: "babel-loader" 8 | } 9 | ] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/es6.js: -------------------------------------------------------------------------------- 1 | export const es6 = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.js$/, 6 | exclude: /node_modules/, 7 | loader: "babel-loader" 8 | } 9 | ] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/es6.js: -------------------------------------------------------------------------------- 1 | export const es6 = { 2 | module: { 3 | rules: [ 4 | { 5 | test: /\.js$/, 6 | exclude: /node_modules/, 7 | loader: "babel-loader" 8 | } 9 | ] 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.app/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.app/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/html.js: -------------------------------------------------------------------------------- 1 | import HtmlWEbpackPlugin from "html-webpack-plugin"; 2 | 3 | export const html = { 4 | plugins: [ 5 | new HtmlWEbpackPlugin({ 6 | template: "index.hbs", 7 | filename: "index.html" 8 | }) 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/html.js: -------------------------------------------------------------------------------- 1 | import HtmlWEbpackPlugin from "html-webpack-plugin"; 2 | 3 | export const html = { 4 | plugins: [ 5 | new HtmlWEbpackPlugin({ 6 | template: "index.hbs", 7 | filename: "index.html" 8 | }) 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/html.js: -------------------------------------------------------------------------------- 1 | import HtmlWEbpackPlugin from "html-webpack-plugin"; 2 | 3 | export const html = { 4 | plugins: [ 5 | new HtmlWEbpackPlugin({ 6 | template: "index.hbs", 7 | filename: "index.html" 8 | }) 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/components/customcarousel/customcarousel.js: -------------------------------------------------------------------------------- 1 | import { Carousel } from "bootstrap"; 2 | 3 | export default () => { 4 | // Initialize all carousels on the page 5 | document.querySelectorAll('.carousel').forEach(carouselEl => { 6 | new Carousel(carouselEl); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.secondapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "categories": [ 4 | "test.categorie.in.config" 5 | ], 6 | "dependencies": [ 7 | "test.base.apps.mainapp" 8 | ], 9 | "embed": [ 10 | "test.base.apps.thirdapp" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/components/customcarousel/customcarousel.js: -------------------------------------------------------------------------------- 1 | import { Carousel } from "bootstrap"; 2 | 3 | export default () => { 4 | // Initialize all carousels on the page 5 | document.querySelectorAll('.carousel').forEach(carouselEl => { 6 | new Carousel(carouselEl); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/components/customcarousel/customcarousel.js: -------------------------------------------------------------------------------- 1 | import { Carousel } from "bootstrap"; 2 | 3 | export default () => { 4 | // Initialize all carousels on the page 5 | document.querySelectorAll('.carousel').forEach(carouselEl => { 6 | new Carousel(carouselEl); 7 | }); 8 | }; 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/path.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const pathConfig = { 4 | paths: { 5 | src: path.resolve("src"), 6 | target: path.resolve("dist"), 7 | public: "public", 8 | styleTarget: "static/styles", 9 | jsTarget: "static/js" 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/path.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const pathConfig = { 4 | paths: { 5 | src: path.resolve("src"), 6 | target: path.resolve("dist"), 7 | public: "public", 8 | styleTarget: "static/styles", 9 | jsTarget: "static/js" 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/path.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | 3 | export const pathConfig = { 4 | paths: { 5 | src: path.resolve("src"), 6 | target: path.resolve("dist"), 7 | public: "public", 8 | styleTarget: "static/styles", 9 | jsTarget: "static/js" 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.five.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "categories": [ 4 | "test.base.apps.five", 5 | "test.categorie.in.config" 6 | ], 7 | "dependencies": [ 8 | "test.base.apps.mainapp" 9 | ], 10 | "embed": [ 11 | "test.base.apps.thirdapp" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/setup/outputConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const output = { 5 | path: path.resolve(pathConfig.paths.target), 6 | filename: `${pathConfig.paths.jsTarget}/[name].js`, 7 | chunkFilename: `${pathConfig.paths.jsTarget}/[name].[hash].js` 8 | }; 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/setup/outputConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const output = { 5 | path: path.resolve(pathConfig.paths.target), 6 | filename: `${pathConfig.paths.jsTarget}/[name].js`, 7 | chunkFilename: `${pathConfig.paths.jsTarget}/[name].[hash].js` 8 | }; 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/setup/outputConfig.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const output = { 5 | path: path.resolve(pathConfig.paths.target), 6 | filename: `${pathConfig.paths.jsTarget}/[name].js`, 7 | chunkFilename: `${pathConfig.paths.jsTarget}/[name].[hash].js` 8 | }; 9 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/redirectOutputTestWithXML/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatXML/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customPropertiesNotAllowed/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.mainapp.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "allowProxy": true, 4 | "categories": [ 5 | "test.base.apps.mainapp" 6 | ], 7 | "cssProcessor": [ 8 | "default:none", 9 | "min:none" 10 | ], 11 | "jsProcessor": [ 12 | "default:none", 13 | "min:gcc" 14 | ], 15 | "longCacheKey": "${project.version}-${buildNumber}" 16 | } 17 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.customProperties/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/clean.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { CleanWebpackPlugin } from "clean-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | const pathsToClean = [pathConfig.paths.target]; 6 | 7 | export const clean = { 8 | plugins: [new CleanWebpackPlugin({ 9 | cleanOnceBeforeBuildPatterns: pathsToClean, 10 | verbose: false 11 | })] 12 | }; 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/clean.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { CleanWebpackPlugin } from "clean-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | const pathsToClean = [pathConfig.paths.target]; 6 | 7 | export const clean = { 8 | plugins: [new CleanWebpackPlugin({ 9 | cleanOnceBeforeBuildPatterns: pathsToClean, 10 | verbose: false 11 | })] 12 | }; 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/clean.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { CleanWebpackPlugin } from "clean-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | const pathsToClean = [pathConfig.paths.target]; 6 | 7 | export const clean = { 8 | plugins: [new CleanWebpackPlugin({ 9 | cleanOnceBeforeBuildPatterns: pathsToClean, 10 | verbose: false 11 | })] 12 | }; 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "browsers": [ 8 | "last 2 versions", 9 | "not dead", 10 | "not op_mini all", 11 | "not < 1%" 12 | ] 13 | } 14 | } 15 | ] 16 | ], 17 | "plugins": ["transform-class-properties", "transform-es2015-arrow-functions"] 18 | } 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "browsers": [ 8 | "last 2 versions", 9 | "not dead", 10 | "not op_mini all", 11 | "not < 1%" 12 | ] 13 | } 14 | } 15 | ] 16 | ], 17 | "plugins": ["transform-class-properties", "transform-es2015-arrow-functions"] 18 | } 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "browsers": [ 8 | "last 2 versions", 9 | "not dead", 10 | "not op_mini all", 11 | "not < 1%" 12 | ] 13 | } 14 | } 15 | ] 16 | ], 17 | "plugins": ["transform-class-properties", "transform-es2015-arrow-functions"] 18 | } 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/index.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { merge } from "webpack-merge"; 3 | 4 | import { pathConfig } from "../../path.config.js"; 5 | import { entry, output } from "./setup/index.js"; 6 | import { clean, es6, scss, handlebars, html, copy } from "./tasks/index.js"; 7 | 8 | export const baseConfig = merge(clean, es6, scss, handlebars, html, copy, { 9 | entry, 10 | output, 11 | context: path.resolve(pathConfig.paths.src) 12 | }); 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/index.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { merge } from "webpack-merge"; 3 | 4 | import { pathConfig } from "../../path.config.js"; 5 | import { entry, output } from "./setup/index.js"; 6 | import { clean, es6, scss, handlebars, html, copy } from "./tasks/index.js"; 7 | 8 | export const baseConfig = merge(clean, es6, scss, handlebars, html, copy, { 9 | entry, 10 | output, 11 | context: path.resolve(pathConfig.paths.src) 12 | }); 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/index.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { merge } from "webpack-merge"; 3 | 4 | import { pathConfig } from "../../path.config.js"; 5 | import { entry, output } from "./setup/index.js"; 6 | import { clean, es6, scss, handlebars, html, copy } from "./tasks/index.js"; 7 | 8 | export const baseConfig = merge(clean, es6, scss, handlebars, html, copy, { 9 | entry, 10 | output, 11 | context: path.resolve(pathConfig.paths.src) 12 | }); 13 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/handlebars.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const handlebars = { 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.hbs$/, 9 | use: [ 10 | { 11 | loader: "handlebars-loader", 12 | options: { 13 | partialDirs: [path.resolve(pathConfig.paths.src)] 14 | } 15 | } 16 | ] 17 | } 18 | ] 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/handlebars.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const handlebars = { 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.hbs$/, 9 | use: [ 10 | { 11 | loader: "handlebars-loader", 12 | options: { 13 | partialDirs: [path.resolve(pathConfig.paths.src)] 14 | } 15 | } 16 | ] 17 | } 18 | ] 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/handlebars.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const handlebars = { 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.hbs$/, 9 | use: [ 10 | { 11 | loader: "handlebars-loader", 12 | options: { 13 | partialDirs: [path.resolve(pathConfig.paths.src)] 14 | } 15 | } 16 | ] 17 | } 18 | ] 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/copy.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import CopyWebpackPlugin from "copy-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | export const copy = { 6 | plugins: [ 7 | new CopyWebpackPlugin({ 8 | patterns: [ 9 | { 10 | from: `${path.resolve(pathConfig.paths.public)}/**/*.*`, 11 | to: `${pathConfig.paths.public}`, 12 | noErrorOnMissing: true, 13 | }, 14 | ], 15 | }), 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | aem-fe-archetype Frontend 10 | 11 | 12 | 13 |
14 | {{> components/customcarousel/customcarousel}} 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/copy.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import CopyWebpackPlugin from "copy-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | export const copy = { 6 | plugins: [ 7 | new CopyWebpackPlugin({ 8 | patterns: [ 9 | { 10 | from: `${path.resolve(pathConfig.paths.public)}/**/*.*`, 11 | to: `${pathConfig.paths.public}`, 12 | noErrorOnMissing: true, 13 | }, 14 | ], 15 | }), 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | aem-fe-archetype Frontend 10 | 11 | 12 | 13 |
14 | {{> components/customcarousel/customcarousel}} 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/copy.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import CopyWebpackPlugin from "copy-webpack-plugin"; 3 | import { pathConfig } from "../../../path.config.js"; 4 | 5 | export const copy = { 6 | plugins: [ 7 | new CopyWebpackPlugin({ 8 | patterns: [ 9 | { 10 | from: `${path.resolve(pathConfig.paths.public)}/**/*.*`, 11 | to: `${pathConfig.paths.public}`, 12 | noErrorOnMissing: true, 13 | }, 14 | ], 15 | }), 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | aem-fe-archetype Frontend 10 | 11 | 12 | 13 |
14 | {{> components/customcarousel/customcarousel}} 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/README.md: -------------------------------------------------------------------------------- 1 | Integration Test: wcmio-archetype 2 | ================================= 3 | 4 | Maven-based Integration test derived from the type of frontend setup generated by [wcm.io Maven Archetype for AEM](https://wcm.io/tooling/maven/archetypes/aem/) 3.x. 5 | 6 | It uses `aem-clientlib-generator` directly from this project as file references in package.json. 7 | 8 | The generated client libraries in the `result` folder are compared against a predefined `existing-result` folder, with a diff-compare after as part of the integration test run. -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/README.md: -------------------------------------------------------------------------------- 1 | Integration Test: wcmio-archetype 2 | ================================= 3 | 4 | Maven-based Integration test derived from the type of frontend setup generated by [wcm.io Maven Archetype for AEM](https://wcm.io/tooling/maven/archetypes/aem/) 3.x. 5 | 6 | It uses `aem-clientlib-generator` directly from this project as file references in package.json. 7 | 8 | The generated client libraries in the `result` folder are compared against a predefined `existing-result` folder, with a diff-compare after as part of the integration test run. -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/README.md: -------------------------------------------------------------------------------- 1 | Integration Test: wcmio-archetype 2 | ================================= 3 | 4 | Maven-based Integration test derived from the type of frontend setup generated by [wcm.io Maven Archetype for AEM](https://wcm.io/tooling/maven/archetypes/aem/) 3.x. 5 | 6 | It uses `aem-clientlib-generator` directly from this project as file references in package.json. 7 | 8 | The generated client libraries in the `result` folder are compared against a predefined `existing-result` folder, with a diff-compare after as part of the integration test run. -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | update_release_draft: 13 | permissions: 14 | contents: write 15 | pull-requests: read 16 | runs-on: ubuntu-latest 17 | steps: 18 | - if: ${{ github.repository_owner == 'wcm-io-frontend' }} 19 | uses: release-drafter/release-drafter@v6 20 | with: 21 | disable-autolabeler: true 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>wcm-io-frontend/renovate-config:npm" 5 | ], 6 | "enabledManagers": [ 7 | "npm", 8 | "nvm", 9 | "maven" 10 | ], 11 | "packageRules": [ 12 | { 13 | "matchUpdateTypes": ["major", "minor", "patch", "pin", "pinDigest", "digest", "lockFileMaintenance"], 14 | "groupName": "integration-test dependencies", 15 | "matchFileNames": ["integration-test/**"], 16 | "schedule": ["before 8am on the first day of the month"], 17 | "automerge": true, 18 | "addLabels": ["integration-test"] 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/expected-result/myproject1.all/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/expected-result/myproject1.all/.content.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Build validation 2 | 3 | name: Build 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | node-version: [lts/*] 18 | os: [ubuntu-latest,windows-latest,macos-latest] 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v5 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v5 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: npm ci 27 | run: npm ci 28 | - name: npm run test 29 | run: npm run test 30 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/expected-result/myproject1.all.json: -------------------------------------------------------------------------------- 1 | { 2 | "jcr:primaryType": "cq:ClientLibraryFolder", 3 | "allowProxy": true, 4 | "categories": [ 5 | "myproject1.all" 6 | ], 7 | "cssProcessor": [ 8 | "default:none", 9 | "min:none" 10 | ], 11 | "embed": [ 12 | "core.wcm.components.commons.datalayer.v1", 13 | "core.wcm.components.commons.site.container", 14 | "core.wcm.components.image.v2", 15 | "core.wcm.components.carousel.v1", 16 | "core.wcm.components.tabs.v1", 17 | "core.wcm.components.accordion.v1", 18 | "myproject1.app" 19 | ], 20 | "jsProcessor": [ 21 | "default:none", 22 | "min:gcc;compilationLevel=whitespace;languageIn=ECMASCRIPT_2018;languageOut=ECMASCRIPT_2018" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/config/webpack/base/tasks/scss.js: -------------------------------------------------------------------------------- 1 | import MiniCssExtractPlugin from "mini-css-extract-plugin"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const scss = { 5 | plugins: [ 6 | new MiniCssExtractPlugin({ 7 | filename: `${pathConfig.paths.styleTarget}/[name].css`, 8 | chunkFilename: `${pathConfig.paths.styleTarget}/[id].css` 9 | }) 10 | ], 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(sa|sc|c)ss$/, 15 | use: [ 16 | { 17 | loader: MiniCssExtractPlugin.loader 18 | }, 19 | { 20 | loader: "css-loader", 21 | options: { 22 | sourceMap: true 23 | } 24 | }, 25 | { 26 | loader: "sass-loader", 27 | options: { 28 | sourceMap: true 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/config/webpack/base/tasks/scss.js: -------------------------------------------------------------------------------- 1 | import MiniCssExtractPlugin from "mini-css-extract-plugin"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const scss = { 5 | plugins: [ 6 | new MiniCssExtractPlugin({ 7 | filename: `${pathConfig.paths.styleTarget}/[name].css`, 8 | chunkFilename: `${pathConfig.paths.styleTarget}/[id].css` 9 | }) 10 | ], 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(sa|sc|c)ss$/, 15 | use: [ 16 | { 17 | loader: MiniCssExtractPlugin.loader 18 | }, 19 | { 20 | loader: "css-loader", 21 | options: { 22 | sourceMap: true 23 | } 24 | }, 25 | { 26 | loader: "sass-loader", 27 | options: { 28 | sourceMap: true 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/config/webpack/base/tasks/scss.js: -------------------------------------------------------------------------------- 1 | import MiniCssExtractPlugin from "mini-css-extract-plugin"; 2 | import { pathConfig } from "../../../path.config.js"; 3 | 4 | export const scss = { 5 | plugins: [ 6 | new MiniCssExtractPlugin({ 7 | filename: `${pathConfig.paths.styleTarget}/[name].css`, 8 | chunkFilename: `${pathConfig.paths.styleTarget}/[id].css` 9 | }) 10 | ], 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.(sa|sc|c)ss$/, 15 | use: [ 16 | { 17 | loader: MiniCssExtractPlugin.loader 18 | }, 19 | { 20 | loader: "css-loader", 21 | options: { 22 | sourceMap: true 23 | } 24 | }, 25 | { 26 | loader: "sass-loader", 27 | options: { 28 | sourceMap: true 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | 3 | import { baseConfig } from "./config/webpack/base/index.js"; 4 | import { devConfig } from "./config/webpack/dev/index.js"; 5 | import { prodConfig } from "./config/webpack/prod/index.js"; 6 | 7 | /** 8 | * Get the configuration file based on webpacks `mode` parameter. 9 | * 10 | * @param {String} runMode - Webpack mode (like: "development", "production", "test", "..."); 11 | */ 12 | const getConfig = runMode => { 13 | switch (runMode) { 14 | case "development": 15 | return devConfig; 16 | case "production": 17 | return prodConfig; 18 | default: 19 | return prodConfig; 20 | } 21 | }; 22 | 23 | /** 24 | * Compose the webpack config 25 | */ 26 | export default (_, argv) => { 27 | const runMode = argv.mode ? argv.mode : "production"; 28 | const runModeConfig = getConfig(runMode); 29 | 30 | return merge(baseConfig, runModeConfig); 31 | }; 32 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | 3 | import { baseConfig } from "./config/webpack/base/index.js"; 4 | import { devConfig } from "./config/webpack/dev/index.js"; 5 | import { prodConfig } from "./config/webpack/prod/index.js"; 6 | 7 | /** 8 | * Get the configuration file based on webpacks `mode` parameter. 9 | * 10 | * @param {String} runMode - Webpack mode (like: "development", "production", "test", "..."); 11 | */ 12 | const getConfig = runMode => { 13 | switch (runMode) { 14 | case "development": 15 | return devConfig; 16 | case "production": 17 | return prodConfig; 18 | default: 19 | return prodConfig; 20 | } 21 | }; 22 | 23 | /** 24 | * Compose the webpack config 25 | */ 26 | export default (_, argv) => { 27 | const runMode = argv.mode ? argv.mode : "production"; 28 | const runModeConfig = getConfig(runMode); 29 | 30 | return merge(baseConfig, runModeConfig); 31 | }; 32 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import { merge } from "webpack-merge"; 2 | 3 | import { baseConfig } from "./config/webpack/base/index.js"; 4 | import { devConfig } from "./config/webpack/dev/index.js"; 5 | import { prodConfig } from "./config/webpack/prod/index.js"; 6 | 7 | /** 8 | * Get the configuration file based on webpacks `mode` parameter. 9 | * 10 | * @param {String} runMode - Webpack mode (like: "development", "production", "test", "..."); 11 | */ 12 | const getConfig = runMode => { 13 | switch (runMode) { 14 | case "development": 15 | return devConfig; 16 | case "production": 17 | return prodConfig; 18 | default: 19 | return prodConfig; 20 | } 21 | }; 22 | 23 | /** 24 | * Compose the webpack config 25 | */ 26 | export default (_, argv) => { 27 | const runMode = argv.mode ? argv.mode : "production"; 28 | const runModeConfig = getConfig(runMode); 29 | 30 | return merge(baseConfig, runModeConfig); 31 | }; 32 | -------------------------------------------------------------------------------- /test/expected/clientlibs-root/test.base.apps.serializationFormatSlingXML.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | test.base.apps.serializationFormatSlingXML 4 | cq:ClientLibraryFolder 5 | 6 | allowProxy 7 | true 8 | Boolean 9 | 10 | 11 | categories 12 | 13 | test.base.apps.six 14 | test.categorie.in.config 15 | 16 | String 17 | 18 | 19 | dependencies 20 | 21 | test.base.apps.mainapp 22 | 23 | String 24 | 25 | 26 | embed 27 | 28 | test.base.apps.thirdapp 29 | 30 | String 31 | 32 | 33 | longCacheKey 34 | ${project.version}-${buildNumber} 35 | String 36 | 37 | 38 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Declare text files with unix file ending 2 | *.conf text eol=lf 3 | *.config text eol=lf 4 | *.css text eol=lf 5 | *.dtd text eol=lf 6 | *.esp text eol=lf 7 | *.ecma text eol=lf 8 | *.groovy text eol=lf 9 | *.hbrs text eol=lf 10 | *.hbs text eol=lf 11 | *.htm text eol=lf 12 | *.html text eol=lf 13 | *.java text eol=lf 14 | *.jpage text eol=lf 15 | *.js text eol=lf 16 | *.json text eol=lf 17 | *.jsp text eol=lf 18 | *.mustache text eol=lf 19 | *.tld text eol=lf 20 | *.launch text eol=lf 21 | *.log text eol=lf 22 | *.php text eol=lf 23 | *.pl text eol=lf 24 | *.project text eol=lf 25 | *.properties text eol=lf 26 | *.props text eol=lf 27 | *.sass text eol=lf 28 | *.scss text eol=lf 29 | *.sh text eol=lf 30 | *.shtm text eol=lf 31 | *.shtml text eol=lf 32 | *.sql text eol=lf 33 | *.svg text eol=lf 34 | *.txt text eol=lf 35 | *.vm text eol=lf 36 | *.xml text eol=lf 37 | *.xsd text eol=lf 38 | *.xsl text eol=lf 39 | *.xslt text eol=lf 40 | *.yml text eol=lf 41 | *.yaml text eol=lf 42 | 43 | 44 | # Declare windows-specific text files with windows file ending 45 | *.asp text eol=crlf 46 | *.asax text eol=crlf 47 | *.asa text eol=crlf 48 | *.aspx text eol=crlf 49 | *.bat text eol=crlf 50 | *.cmd text eol=crlf 51 | *.cs text eol=crlf 52 | *.csproj text eol=crlf 53 | *.reg text eol=crlf 54 | *.sln text eol=crlf 55 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/clientlib.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // default working directory (can be changed per 'cwd' in every asset option) 3 | context: __dirname, 4 | 5 | // path to the clientlib root folder (output) 6 | clientLibRoot: "result", 7 | 8 | // define all clientlib options here as array... (multiple clientlibs) 9 | libs: [ 10 | { 11 | name: "myproject1.app", 12 | serializationFormat: "json", 13 | allowProxy: true, 14 | assets: { 15 | js: ["dist/static/js/app.js", "dist/static/js/app.js.map"], 16 | css: ["dist/static/styles/app.css", "dist/static/styles/app.css.map"], 17 | resources: { 18 | cwd: "./public/", 19 | flatten: false, 20 | files: ["**/*.*"] 21 | } 22 | } 23 | }, 24 | { 25 | name: "myproject1.all", 26 | serializationFormat: "json", 27 | embed: [ 28 | "core.wcm.components.commons.datalayer.v1", 29 | "core.wcm.components.commons.site.container", 30 | "core.wcm.components.image.v2", 31 | "core.wcm.components.carousel.v1", 32 | "core.wcm.components.tabs.v1", 33 | "core.wcm.components.accordion.v1", 34 | "myproject1.app" 35 | ], 36 | jsProcessor: ["default:none", "min:gcc;compilationLevel=whitespace;languageIn=ECMASCRIPT_2018;languageOut=ECMASCRIPT_2018"], 37 | cssProcessor: ["default:none", "min:none"], 38 | allowProxy: true, 39 | assets: { 40 | js: [], 41 | css: [] 42 | } 43 | } 44 | ] 45 | }; 46 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/clientlib.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // default working directory (can be changed per 'cwd' in every asset option) 3 | context: __dirname, 4 | 5 | // path to the clientlib root folder (output) 6 | clientLibRoot: "result", 7 | 8 | // define all clientlib options here as array... (multiple clientlibs) 9 | libs: [ 10 | { 11 | name: "myproject1.app", 12 | serializationFormat: "xml", 13 | allowProxy: true, 14 | assets: { 15 | js: ["dist/static/js/app.js", "dist/static/js/app.js.map"], 16 | css: ["dist/static/styles/app.css", "dist/static/styles/app.css.map"], 17 | resources: { 18 | cwd: "./public/", 19 | flatten: false, 20 | files: ["**/*.*"] 21 | } 22 | } 23 | }, 24 | { 25 | name: "myproject1.all", 26 | serializationFormat: "xml", 27 | embed: [ 28 | "core.wcm.components.commons.datalayer.v1", 29 | "core.wcm.components.commons.site.container", 30 | "core.wcm.components.image.v2", 31 | "core.wcm.components.carousel.v1", 32 | "core.wcm.components.tabs.v1", 33 | "core.wcm.components.accordion.v1", 34 | "myproject1.app" 35 | ], 36 | jsProcessor: ["default:none", "min:gcc;compilationLevel=whitespace;languageIn=ECMASCRIPT_2018;languageOut=ECMASCRIPT_2018"], 37 | cssProcessor: ["default:none", "min:none"], 38 | allowProxy: true, 39 | assets: { 40 | js: [], 41 | css: [] 42 | } 43 | } 44 | ] 45 | }; 46 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/clientlib.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | // default working directory (can be changed per 'cwd' in every asset option) 3 | context: import.meta.dirname, 4 | 5 | // path to the clientlib root folder (output) 6 | clientLibRoot: "result", 7 | 8 | // define all clientlib options here as array... (multiple clientlibs) 9 | libs: [ 10 | { 11 | name: "myproject1.app", 12 | serializationFormat: "xml", 13 | allowProxy: true, 14 | assets: { 15 | js: ["dist/static/js/app.js", "dist/static/js/app.js.map"], 16 | css: ["dist/static/styles/app.css", "dist/static/styles/app.css.map"], 17 | resources: { 18 | cwd: "./public/", 19 | flatten: false, 20 | files: ["**/*.*"] 21 | } 22 | } 23 | }, 24 | { 25 | name: "myproject1.all", 26 | serializationFormat: "xml", 27 | embed: [ 28 | "core.wcm.components.commons.datalayer.v1", 29 | "core.wcm.components.commons.site.container", 30 | "core.wcm.components.image.v2", 31 | "core.wcm.components.carousel.v1", 32 | "core.wcm.components.tabs.v1", 33 | "core.wcm.components.accordion.v1", 34 | "myproject1.app" 35 | ], 36 | jsProcessor: ["default:none", "min:gcc;compilationLevel=whitespace;languageIn=ECMASCRIPT_2018;languageOut=ECMASCRIPT_2018"], 37 | cssProcessor: ["default:none", "min:none"], 38 | allowProxy: true, 39 | assets: { 40 | js: [], 41 | css: [] 42 | } 43 | } 44 | ] 45 | }; 46 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "myproject1-frontend", 4 | "version": "1.0.0", 5 | "description": "Frontend build pipeline for AEM projects", 6 | "main": "index.js", 7 | "scripts": { 8 | "start": "webpack-dev-server --mode development --open", 9 | "build:dev": "webpack --mode development", 10 | "build:prod": "webpack --mode production", 11 | "build:clientlibs": "npm run build:prod && node ../../bin/clientlib-cli.js", 12 | "test:compare-results": "node compare-results.mjs" 13 | }, 14 | "dependencies": { 15 | "bootstrap": "5.3.8", 16 | "@popperjs/core": "2.11.8" 17 | }, 18 | "devDependencies": { 19 | "dir-compare": "5.0.0", 20 | "diff": "8.0.2", 21 | "@babel/core": "7.28.5", 22 | "@babel/preset-env": "7.28.5", 23 | "@babel/register": "7.28.3", 24 | "aem-clientlib-generator": "file:../../..", 25 | "babel-loader": "10.0.0", 26 | "babel-plugin-transform-class-properties": "6.24.1", 27 | "babel-plugin-transform-es2015-arrow-functions": "6.22.0", 28 | "clean-webpack-plugin": "4.0.0", 29 | "copy-webpack-plugin": "13.0.1", 30 | "css-loader": "7.1.2", 31 | "handlebars": "4.7.8", 32 | "handlebars-loader": "1.7.3", 33 | "html-webpack-plugin": "5.6.4", 34 | "mini-css-extract-plugin": "2.9.4", 35 | "postcss-loader": "8.2.0", 36 | "sass": "1.93.2", 37 | "sass-loader": "16.0.6", 38 | "webpack": "5.102.1", 39 | "webpack-cli": "6.0.1", 40 | "webpack-dev-server": "5.2.2", 41 | "webpack-merge": "6.0.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aem-clientlib-generator", 3 | "version": "1.10.0", 4 | "description": "Creates configuration files for AEM ClientLibs and synchronizes assets.", 5 | "author": { 6 | "name": "wcm.io", 7 | "url": "https://wcm.io" 8 | }, 9 | "type": "module", 10 | "contributors": [ 11 | { 12 | "name": "Ingo Fahrentholz" 13 | }, 14 | { 15 | "name": "Masoud Rozati" 16 | }, 17 | { 18 | "name": "Mehran Behzad" 19 | }, 20 | { 21 | "name": "Bert-Ulrich Baumann" 22 | } 23 | ], 24 | "homepage": "https://github.com/wcm-io-frontend/aem-clientlib-generator", 25 | "bugs": { 26 | "url": "https://github.com/wcm-io-frontend/aem-clientlib-generator/issues" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/wcm-io-frontend/aem-clientlib-generator.git" 31 | }, 32 | "engines": { 33 | "node": ">=10.19.0" 34 | }, 35 | "keywords": [ 36 | "aem", 37 | "clientlib", 38 | "clientlibs", 39 | "generator", 40 | "sync" 41 | ], 42 | "main": "lib/clientlib.js", 43 | "bin": { 44 | "clientlib": "bin/clientlib-cli.js" 45 | }, 46 | "dependencies": { 47 | "async": "^3.2.3", 48 | "fs-extra": "11.3.2", 49 | "glob": "7.2.3", 50 | "lodash": "4.17.21", 51 | "yargs": "^18.0.0" 52 | }, 53 | "devDependencies": { 54 | "klaw": "4.1.0", 55 | "mocha": "11.7.5" 56 | }, 57 | "license": "Apache-2.0", 58 | "scripts": { 59 | "test": "mocha", 60 | "build": "bin/clientlib-cli.js test/clientlib.config.js --verbose" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "myproject1-frontend", 4 | "version": "1.0.0", 5 | "description": "Frontend build pipeline for AEM projects", 6 | "main": "index.js", 7 | "type": "module", 8 | "scripts": { 9 | "start": "webpack-dev-server --mode development --open", 10 | "build:dev": "webpack --mode development", 11 | "build:prod": "webpack --mode production", 12 | "build:clientlibs": "npm run build:prod && node ../../bin/clientlib-cli.js", 13 | "test:compare-results": "node compare-results.js" 14 | }, 15 | "dependencies": { 16 | "bootstrap": "5.3.8", 17 | "@popperjs/core": "2.11.8" 18 | }, 19 | "devDependencies": { 20 | "dir-compare": "5.0.0", 21 | "diff": "8.0.2", 22 | "@babel/core": "7.28.5", 23 | "@babel/preset-env": "7.28.5", 24 | "@babel/register": "7.28.3", 25 | "aem-clientlib-generator": "file:../../..", 26 | "babel-loader": "10.0.0", 27 | "babel-plugin-transform-class-properties": "6.24.1", 28 | "babel-plugin-transform-es2015-arrow-functions": "6.22.0", 29 | "clean-webpack-plugin": "4.0.0", 30 | "copy-webpack-plugin": "13.0.1", 31 | "css-loader": "7.1.2", 32 | "handlebars": "4.7.8", 33 | "handlebars-loader": "1.7.3", 34 | "html-webpack-plugin": "5.6.4", 35 | "mini-css-extract-plugin": "2.9.4", 36 | "postcss-loader": "8.2.0", 37 | "sass": "1.93.2", 38 | "sass-loader": "16.0.6", 39 | "webpack": "5.102.1", 40 | "webpack-cli": "6.0.1", 41 | "webpack-dev-server": "5.2.2", 42 | "webpack-merge": "6.0.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "myproject1-frontend", 4 | "version": "1.0.0", 5 | "description": "Frontend build pipeline for AEM projects", 6 | "main": "index.js", 7 | "type": "module", 8 | "scripts": { 9 | "start": "webpack-dev-server --mode development --open", 10 | "build:dev": "webpack --mode development", 11 | "build:prod": "webpack --mode production", 12 | "build:clientlibs": "npm run build:prod && node ../../bin/clientlib-cli.js clientlib.config.cjs", 13 | "test:compare-results": "node compare-results.js" 14 | }, 15 | "dependencies": { 16 | "bootstrap": "5.3.8", 17 | "@popperjs/core": "2.11.8" 18 | }, 19 | "devDependencies": { 20 | "dir-compare": "5.0.0", 21 | "diff": "8.0.2", 22 | "@babel/core": "7.28.5", 23 | "@babel/preset-env": "7.28.5", 24 | "@babel/register": "7.28.3", 25 | "aem-clientlib-generator": "file:../../..", 26 | "babel-loader": "10.0.0", 27 | "babel-plugin-transform-class-properties": "6.24.1", 28 | "babel-plugin-transform-es2015-arrow-functions": "6.22.0", 29 | "clean-webpack-plugin": "4.0.0", 30 | "copy-webpack-plugin": "13.0.1", 31 | "css-loader": "7.1.2", 32 | "handlebars": "4.7.8", 33 | "handlebars-loader": "1.7.3", 34 | "html-webpack-plugin": "5.6.4", 35 | "mini-css-extract-plugin": "2.9.4", 36 | "postcss-loader": "8.2.0", 37 | "sass": "1.93.2", 38 | "sass-loader": "16.0.6", 39 | "webpack": "5.102.1", 40 | "webpack-cli": "6.0.1", 41 | "webpack-dev-server": "5.2.2", 42 | "webpack-merge": "6.0.1" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/src/components/customcarousel/customcarousel.hbs: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/src/components/customcarousel/customcarousel.hbs: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/src/components/customcarousel/customcarousel.hbs: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /bin/clientlib-cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import url from 'node:url'; 4 | 5 | var DEFAULT_FILE = "clientlib.config.js"; 6 | import clientlib from "../lib/clientlib.js"; 7 | 8 | import path from "node:path"; 9 | import fs from "fs"; 10 | import yargs from "yargs" 11 | import { hideBin } from "yargs/helpers" 12 | 13 | var argv = yargs(hideBin(process.argv)) 14 | .usage("aem-clientlib-generator " + process.env.npm_package_version + "\n" + 15 | "Usage with config file: clientlib [path] [options]" + "\n\n" + 16 | "Default config path: " + DEFAULT_FILE) 17 | .help("help") 18 | .alias("help", "h") 19 | .version() 20 | .alias("version", "v") 21 | .options({ 22 | "dry": { 23 | type: "boolean", 24 | describe: "'Dry run' without write operations." 25 | }, 26 | "verbose": { 27 | type: "boolean", 28 | describe: "Prints more details" 29 | } 30 | }).argv; 31 | 32 | var configPath = path.resolve(process.cwd(), DEFAULT_FILE); 33 | 34 | if (argv._ && argv._.length > 0) { 35 | configPath = argv._[0]; 36 | if (!path.isAbsolute(configPath)) { 37 | configPath = path.resolve(process.cwd(), configPath); 38 | } 39 | } 40 | 41 | if (!fs.existsSync(configPath)) { 42 | console.error("Could not find config file: " + configPath); 43 | process.exit(1); 44 | } 45 | 46 | import(path.isAbsolute(configPath) ? url.pathToFileURL(configPath).toString() : configPath ).then(conf => { 47 | var libs = [...conf.default.libs]; 48 | var clientLibConf = conf.default; 49 | delete conf.default.libs; 50 | clientLibConf.dry = argv.dry; 51 | clientLibConf.verbose = argv.verbose || argv.dry; 52 | 53 | clientlib(libs, clientLibConf); 54 | }).catch(err => console.error(err)); 55 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/compare-results.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import dircompare from 'dir-compare'; 3 | import path from 'path'; 4 | import { fileURLToPath } from 'url'; 5 | import fs from 'fs'; 6 | import * as diff from 'diff'; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | const resultDir = path.join(__dirname, 'result'); 12 | const expectedDir = path.join(__dirname, 'expected-result'); 13 | 14 | const options = { compareContent: true, excludeFilter: '.DS_Store' }; 15 | const res = dircompare.compareSync(resultDir, expectedDir, options); 16 | 17 | if (!res.same) { 18 | console.error('Differences found:'); 19 | for (const e of res.diffSet.filter(e => e.state !== 'equal')) { 20 | const name1 = e.name1 ? e.name1 : ''; 21 | const name2 = e.name2 ? e.name2 : ''; 22 | const relPath = e.relativePath; 23 | const file1 = path.join(resultDir, relPath, name1); 24 | const file2 = path.join(expectedDir, relPath, name2); 25 | if (e.type1 === 'missing') { 26 | console.error(`Only in expected-result: ${path.join(relPath, name2)}`); 27 | } else if (e.type2 === 'missing') { 28 | console.error(`Only in result: ${path.join(relPath, name1)}`); 29 | } else { 30 | console.error(`Diff: ${path.join(relPath, name1)}`); 31 | try { 32 | const a = fs.readFileSync(file1, 'utf8'); 33 | const b = fs.readFileSync(file2, 'utf8'); 34 | // Show unified diff 35 | const diffLines = diff.createPatch(name1, b, a, 'expected', 'result'); 36 | console.error(diffLines); 37 | } catch (err) { 38 | console.error(' (Could not show file diff)', err.message); 39 | } 40 | } 41 | } 42 | process.exit(1); 43 | } else { 44 | console.log('All files match.'); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/compare-results.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import dircompare from 'dir-compare'; 3 | import path from 'path'; 4 | import { fileURLToPath } from 'url'; 5 | import fs from 'fs'; 6 | import * as diff from 'diff'; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | const resultDir = path.join(__dirname, 'result'); 12 | const expectedDir = path.join(__dirname, 'expected-result'); 13 | 14 | const options = { compareContent: true, excludeFilter: '.DS_Store' }; 15 | const res = dircompare.compareSync(resultDir, expectedDir, options); 16 | 17 | if (!res.same) { 18 | console.error('Differences found:'); 19 | for (const e of res.diffSet.filter(e => e.state !== 'equal')) { 20 | const name1 = e.name1 ? e.name1 : ''; 21 | const name2 = e.name2 ? e.name2 : ''; 22 | const relPath = e.relativePath; 23 | const file1 = path.join(resultDir, relPath, name1); 24 | const file2 = path.join(expectedDir, relPath, name2); 25 | if (e.type1 === 'missing') { 26 | console.error(`Only in expected-result: ${path.join(relPath, name2)}`); 27 | } else if (e.type2 === 'missing') { 28 | console.error(`Only in result: ${path.join(relPath, name1)}`); 29 | } else { 30 | console.error(`Diff: ${path.join(relPath, name1)}`); 31 | try { 32 | const a = fs.readFileSync(file1, 'utf8'); 33 | const b = fs.readFileSync(file2, 'utf8'); 34 | // Show unified diff 35 | const diffLines = diff.createPatch(name1, b, a, 'expected', 'result'); 36 | console.error(diffLines); 37 | } catch (err) { 38 | console.error(' (Could not show file diff)', err.message); 39 | } 40 | } 41 | } 42 | process.exit(1); 43 | } else { 44 | console.log('All files match.'); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/compare-results.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import dircompare from 'dir-compare'; 3 | import path from 'path'; 4 | import { fileURLToPath } from 'url'; 5 | import fs from 'fs'; 6 | import * as diff from 'diff'; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | const resultDir = path.join(__dirname, 'result'); 12 | const expectedDir = path.join(__dirname, 'expected-result'); 13 | 14 | const options = { compareContent: true, excludeFilter: '.DS_Store' }; 15 | const res = dircompare.compareSync(resultDir, expectedDir, options); 16 | 17 | if (!res.same) { 18 | console.error('Differences found:'); 19 | for (const e of res.diffSet.filter(e => e.state !== 'equal')) { 20 | const name1 = e.name1 ? e.name1 : ''; 21 | const name2 = e.name2 ? e.name2 : ''; 22 | const relPath = e.relativePath; 23 | const file1 = path.join(resultDir, relPath, name1); 24 | const file2 = path.join(expectedDir, relPath, name2); 25 | if (e.type1 === 'missing') { 26 | console.error(`Only in expected-result: ${path.join(relPath, name2)}`); 27 | } else if (e.type2 === 'missing') { 28 | console.error(`Only in result: ${path.join(relPath, name1)}`); 29 | } else { 30 | console.error(`Diff: ${path.join(relPath, name1)}`); 31 | try { 32 | const a = fs.readFileSync(file1, 'utf8'); 33 | const b = fs.readFileSync(file2, 'utf8'); 34 | // Show unified diff 35 | const diffLines = diff.createPatch(name1, b, a, 'expected', 'result'); 36 | console.error(diffLines); 37 | } catch (err) { 38 | console.error(' (Could not show file diff)', err.message); 39 | } 40 | } 41 | } 42 | process.exit(1); 43 | } else { 44 | console.log('All files match.'); 45 | } 46 | 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release and Publish 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | description: Type of release (e.g., patch, minor, major) 8 | required: true 9 | default: patch 10 | 11 | permissions: 12 | contents: read 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v5 19 | 20 | - uses: actions/setup-node@v5 21 | with: 22 | node-version: lts/* 23 | cache: npm 24 | 25 | - run: npm ci 26 | - run: npm run test 27 | 28 | release-and-publish-npm-registry: 29 | needs: build 30 | runs-on: ubuntu-latest 31 | 32 | permissions: 33 | id-token: write 34 | contents: write 35 | pull-requests: read 36 | 37 | steps: 38 | - uses: actions/checkout@v5 39 | with: 40 | fetch-depth: 0 41 | 42 | - uses: actions/setup-node@v5 43 | with: 44 | node-version: lts/* 45 | cache: npm 46 | registry-url: https://registry.npmjs.org 47 | 48 | - name: set next version 49 | run: | 50 | git config user.name "GitHub Actions" 51 | git config user.email noreply@github.com 52 | npm version ${{ github.event.inputs.release_type }} -m "[npm] Release %s" 53 | git push 54 | shell: bash 55 | 56 | - run: npm ci 57 | - run: npm publish --provenance --access public 58 | env: 59 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 60 | 61 | - name: Read properties from package.json 62 | id: package_json 63 | uses: zoexx/github-action-json-file-properties@1.0.6 64 | with: 65 | file_path: package.json 66 | 67 | - uses: release-drafter/release-drafter@v6 68 | with: 69 | disable-autolabeler: true 70 | name: ${{ steps.package_json.outputs.version }} 71 | tag: ${{ steps.package_json.outputs.version }} 72 | version: ${{ steps.package_json.outputs.version }} 73 | publish: true 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | -------------------------------------------------------------------------------- /.github/workflows/integration-tests.yml: -------------------------------------------------------------------------------- 1 | # Integration Tests 2 | 3 | name: Integration Tests 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | workflow_dispatch: 11 | 12 | jobs: 13 | integration-tests: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | java-version: [21] 18 | node-version: [lts/*] 19 | os: [ubuntu-latest,windows-latest,macos-latest] 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v5 23 | - name: Use Java ${{ matrix.java-version }} 24 | uses: actions/setup-java@v5 25 | with: 26 | distribution: temurin 27 | java-version: ${{ matrix.java-version }} 28 | cache: maven 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v5 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | - name: npm ci 34 | run: npm ci 35 | 36 | - name: "Integration Test: wcmio-archetype-module" 37 | run: mvn clean verify 38 | working-directory: integration-test/wcmio-archetype-module 39 | - uses: actions/upload-artifact@v4 40 | if: always() 41 | with: 42 | name: wcmio-archetype-module-result-${{ matrix.os }}-java${{ matrix.java-version }} 43 | path: integration-test/wcmio-archetype-module/result/ 44 | if-no-files-found: warn 45 | include-hidden-files: true 46 | 47 | - name: "Integration Test: wcmio-archetype-module-cjs" 48 | run: mvn clean verify 49 | working-directory: integration-test/wcmio-archetype-module-cjs 50 | - uses: actions/upload-artifact@v4 51 | if: always() 52 | with: 53 | name: wcmio-archetype-module-cjs-result-${{ matrix.os }}-java${{ matrix.java-version }} 54 | path: integration-test/wcmio-archetype-module-cjs/result/ 55 | if-no-files-found: warn 56 | include-hidden-files: true 57 | 58 | - name: "Integration Test: wcmio-archetype-commonjs" 59 | run: mvn clean verify 60 | working-directory: integration-test/wcmio-archetype-commonjs 61 | - uses: actions/upload-artifact@v4 62 | if: always() 63 | with: 64 | name: wcmio-archetype-commonjs-result-${{ matrix.os }}-java${{ matrix.java-version }} 65 | path: integration-test/wcmio-archetype-commonjs/result/ 66 | if-no-files-found: warn 67 | include-hidden-files: true 68 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-commonjs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.wcm.maven 7 | io.wcm.maven.aem-global-parent 8 | 2.2.2 9 | 10 | 11 | 12 | aem-clientlib-generator.it 13 | wcmio-archetype 14 | 1.0.0-SNAPSHOT 15 | pom 16 | 17 | 18 | v22.15.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | com.github.eirslett 27 | frontend-maven-plugin 28 | 29 | 30 | install node and npm 31 | 32 | install-node-and-npm 33 | 34 | process-resources 35 | 36 | ${nodejs.version} 37 | 38 | 39 | 40 | npm install 41 | 42 | npm 43 | 44 | process-resources 45 | 46 | install 47 | 48 | 49 | 50 | npm build:clientlibs 51 | 52 | npm 53 | 54 | process-resources 55 | 56 | run build:clientlibs 57 | 58 | 59 | 60 | npm test:compare-results 61 | 62 | npm 63 | 64 | process-resources 65 | 66 | run test:compare-results 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.wcm.maven 7 | io.wcm.maven.aem-global-parent 8 | 2.2.2 9 | 10 | 11 | 12 | aem-clientlib-generator.it 13 | wcmio-archetype 14 | 1.0.0-SNAPSHOT 15 | pom 16 | 17 | 18 | v22.15.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | com.github.eirslett 27 | frontend-maven-plugin 28 | 29 | 30 | install node and npm 31 | 32 | install-node-and-npm 33 | 34 | process-resources 35 | 36 | ${nodejs.version} 37 | 38 | 39 | 40 | npm install 41 | 42 | npm 43 | 44 | process-resources 45 | 46 | install 47 | 48 | 49 | 50 | npm build:clientlibs 51 | 52 | npm 53 | 54 | process-resources 55 | 56 | run build:clientlibs 57 | 58 | 59 | 60 | npm test:compare-results 61 | 62 | npm 63 | 64 | process-resources 65 | 66 | run test:compare-results 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /integration-test/wcmio-archetype-module-cjs/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | io.wcm.maven 7 | io.wcm.maven.aem-global-parent 8 | 2.2.2 9 | 10 | 11 | 12 | aem-clientlib-generator.it 13 | wcmio-archetype 14 | 1.0.0-SNAPSHOT 15 | pom 16 | 17 | 18 | v22.15.0 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | com.github.eirslett 27 | frontend-maven-plugin 28 | 29 | 30 | install node and npm 31 | 32 | install-node-and-npm 33 | 34 | process-resources 35 | 36 | ${nodejs.version} 37 | 38 | 39 | 40 | npm install 41 | 42 | npm 43 | 44 | process-resources 45 | 46 | install 47 | 48 | 49 | 50 | npm build:clientlibs 51 | 52 | npm 53 | 54 | process-resources 55 | 56 | run build:clientlibs 57 | 58 | 59 | 60 | npm test:compare-results 61 | 62 | npm 63 | 64 | process-resources 65 | 66 | run test:compare-results 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /test/TestCase.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 wcm.io and Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | import fs from "fs"; 21 | import walk from "klaw"; 22 | import fse from "fs-extra"; 23 | import clientlib, { fileExists } from "../lib/clientlib.js"; 24 | import path from "path"; 25 | import { fileURLToPath } from "url"; 26 | import assert from "assert"; 27 | 28 | import clientLibConf from "./clientlib.config.js"; 29 | 30 | const __filename = fileURLToPath(import.meta.url); 31 | const __dirname = path.dirname(__filename); 32 | 33 | var resultDir = path.join(__dirname, "result"); 34 | var expectedDir = path.join(__dirname, "expected"); 35 | 36 | 37 | describe("Test output", function() { 38 | 39 | // cleanup result folder 40 | beforeEach(function(){ 41 | fse.removeSync(resultDir); 42 | fs.mkdirSync(resultDir); 43 | }); 44 | 45 | it("should create files correctly", function(done) { 46 | 47 | var libs = clientLibConf.libs; 48 | delete clientLibConf.libs; 49 | 50 | clientlib(libs, clientLibConf, function() { 51 | 52 | var items = []; // files, directories, symlinks, etc 53 | walk(expectedDir) 54 | .on("data", function (item) { 55 | items.push(item.path) 56 | }) 57 | .on("end", function () { 58 | 59 | items.forEach(function(expectedFile) { 60 | var subFilePath = path.relative(expectedDir, expectedFile); 61 | if (!subFilePath) { 62 | return; 63 | } 64 | 65 | var resultFile = path.join(resultDir, subFilePath); 66 | 67 | assert.ok(fileExists(resultFile), "file does not exist in result: " + subFilePath); 68 | 69 | if (!fs.lstatSync(expectedFile).isDirectory()) { 70 | var result = fs.readFileSync(resultFile, "utf-8").replace(/\r\n/g, "\n"); 71 | var expected = fs.readFileSync(expectedFile, "utf-8").replace(/\r\n/g, "\n"); 72 | 73 | assert.equal(result, expected, "content of " + subFilePath + " is not expected"); 74 | } 75 | 76 | }); 77 | 78 | done(); 79 | }); 80 | }); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aem-clientlib-generator 2 | ====== 3 | [![Build](https://github.com/wcm-io-frontend/aem-clientlib-generator/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/wcm-io-frontend/aem-clientlib-generator/actions?query=workflow%3ABuild) 4 | [![GitHub issues](https://img.shields.io/github/issues/wcm-io-frontend/aem-clientlib-generator)](https://github.com/wcm-io-frontend/aem-clientlib-generator/issues) 5 | 6 | A node plugin that creates ClientLib configuration files (repository nodes) for 7 | [AEM Client Libraries](https://helpx.adobe.com/experience-manager/6-3/sites/developing/using/clientlibs.html), 8 | creates _Client Library Folders_ and synchronizes all assets. 9 | 10 | It supports both JSON file format (default) and FileVault XML file format (see `serializationFormat` parameter). 11 | 12 | ## Installation 13 | 14 | ```bash 15 | npm install aem-clientlib-generator 16 | ``` 17 | 18 | ## Usage 19 | 20 | ### Command Line Interface 21 | 22 | The CLI `clientlib` is located in `./bin/clientlib-cli.js`. 23 | The command can be used without parameters, it loads the default configuration file `clientlib.config.js`. 24 | More options are described in help menu: 25 | 26 | ```text 27 | Options: 28 | --help, -h Show help [boolean] 29 | --version, -v Show version number [boolean] 30 | --dry 'Dry run' without write operations. [boolean] 31 | --verbose Prints more details [boolean] 32 | ``` 33 | 34 | #### clientlib.config.js 35 | 36 | A clientlib configuration file is a simple exported module: 37 | 38 | ```js 39 | export default { 40 | // default working directory (can be changed per 'cwd' in every asset option) 41 | context: import.meta.dirname, 42 | 43 | // path to the clientlib root folder (output) 44 | clientLibRoot: "path/to/clientlib-root", 45 | 46 | // define all clientlib options here as array... (multiple clientlibs) 47 | libs: [ 48 | { 49 | name: "test.base.apps.mainapp", 50 | 51 | // optional override path to write clientlib files to, by default files 52 | // are written to lib.name/ 53 | outputPath: "explicit/path/to/lib/or/existing/lib/structure", 54 | 55 | assets: { 56 | js: [ 57 | "src/frontend/js/app.js" 58 | ], 59 | css: [ 60 | "src/frontend/css/styling.css" 61 | ] 62 | } 63 | }, 64 | ...// next clientlibs 65 | ], 66 | 67 | // or as object (single clientlib) 68 | libs: { 69 | name: "test.base.apps.mainapp", 70 | assets: { 71 | js: [ 72 | "src/frontend/js/app.js" 73 | ], 74 | css: [ 75 | "src/frontend/css/styling.css" 76 | ] 77 | } 78 | } 79 | }; 80 | ``` 81 | 82 | #### npm scripts 83 | 84 | The CLI can be used in a project as local module via npm scripts (defined in `package.json`). 85 | 86 | ```js 87 | // package.json file: 88 | 89 | "scripts": { 90 | "test": "mocha", 91 | "build": "clientlib --verbose" 92 | } 93 | ``` 94 | 95 | In this case `npm run build` tries to load the default clientlib configuration file 96 | `clientlib.config.js` (same directory like package.json) and generates all clientslib 97 | as defined. 98 | 99 | ### Module: clientlib(arrProps | props, [options], callback) 100 | 101 | Import the module into a JavaScript file and run the module as a function: 102 | 103 | ```js 104 | var clientlib = require("aem-clientlib-generator"); 105 | clientlib(arrProps, { verbose: true }, function () { 106 | console.log("generator has finished"); 107 | }); 108 | ``` 109 | 110 | **Important:** Due to many write operations, the `clientlib` function is **asynchronous**! 111 | 112 | - `arrProps` `{Array}` Array of Clientlib configuration properties (see below) 113 | - `props` `{Object}` Clientlib configuration properties 114 | 115 | - `path` `{String}` Clientlib root path (optional if `options.clientLibRoot` is set) 116 | - `outputPath` `{String}` Clientlib destination path (optional, overrides default behavior of writing to the above path or options.clientLibRoot, useful to supply your own directory naming convention or if you are clientlib-ifying an existing directory) 117 | - `name` `{String}` Clientlib name (required) 118 | - `serializationFormat` `{String}` Type of the target archive for which the resources must be generated [json|xml] (optional, default=json) 119 | - `embed` `{Array}` other Clientlib names that should be embedded (optional) 120 | - `dependencies` `{Array}` other Clientlib names that should be included (optional) 121 | - `categories` `{Array}` to set a category for the clientLib (optional), ovrrides the default that uses the name as category 122 | - `customProperties` `{Array}` by default only a set of known properties will be copied over the clientlib, using this field custom properties can be added 123 | - `cssProcessor` `{Array}` configuration for the clientlib CSS processor, requires AEM 6.2 (optional) 124 | - `jsProcessor` `{Array}` configuration for the clientlib JS processor, requires AEM 6.2 (optional) 125 | - `replaces` `{String}` Path to the library that is replaced by 'this' one 126 | - `disableIfReplacing` `{boolean}` Disable this library if it would replace the old one 127 | - `assets` `{Object}` content that should be copied to the clientlib folder, more details below (required) 128 | - `allowProxy` `{Boolean}` allow for Clientlib creation under `/apps/myapp/clientLibs` but enable proxy to `/etc.clientlibs/myapp/clientlibs/mylib` See [AEM 6.3 Documentation](https://docs.adobe.com/docs/en/aem/6-3/develop/the-basics/clientlibs.html#Locating%20a%20Client%20Library%20Folder%20and%20Using%20the%20Proxy%20Client%20Libraries%20Servlet) 129 | - `longCacheKey` `{String}` optional string with placeholders to use with URL Fingerprinting, eq. `"${project.version}-${buildNumber}"`. This requires the [build-helper-maven-plugin](http://www.mojohaus.org/build-helper-maven-plugin/usage.html) to be configured, see [wcm-io-samples - Clientlibs](https://github.com/wcm-io/wcm-io-samples/blob/develop/bundles/clientlibs/pom.xml#L56). 130 | 131 | - `options` `{Object}` global options to be used for all clientlib definitions (optional) 132 | - `clientLibRoot` {String} Clientlib root path 133 | - `context` {String} changes the current working directory (via `process.chdir()`) 134 | - `cwd` {String} alias for `context` 135 | - `verbose` {Boolean} prints detailed information during generation 136 | - `dry` {Boolean} dry run without file write operations (sets automatically verbose to true) 137 | 138 | * `callback` `{Function}` to be called if clientlib() has finished 139 | 140 | ### The `assets` Object 141 | 142 | The `assets` object determine the content that should be pushed into the clientlib folder. The key stands for 143 | the content type, `js` for JavaScript files, `css` for styles and `resources` for other content such as 144 | fonts or images. 145 | 146 | ```javascript 147 | { 148 | js: { 149 | // JavaScript files to be copied and used for `js.txt` - a clientlib JS configuration file 150 | }, 151 | css: { 152 | // CSS files to be copied and used for `css.txt` - a clientlib CSS configuration file 153 | }, 154 | resources: { 155 | // other resources that should be copied 156 | } 157 | } 158 | ``` 159 | 160 | Each property can be an object of deeper configuration options (`assetConfig`) or an array of files (simple way, see example below). 161 | The following can be configured: 162 | 163 | - `assetConfig` `{Object}` Configuration object for an asset type 164 | - `base` `{String}` path within the clientlib folder where the data should be copied to (optional), default: asset key, e.g. for "js" is the base "js" 165 | - Hint: Using "." copies the files into the clientlib folder instead of the subfolder 166 | - `files` `{Array}` array of file paths (sources) or a src-dest key value map (required) 167 | - Important: The order of JS or CSS files in this property defines the merging/bundling order in AEM clientlib. 168 | - file object contains: 169 | - `src` {String} - source file relative to the current working directory or the global `cwd` option, if set 170 | - `dest` {String} - destination relative to the clientlib folder including base 171 | - `cwd` {String} - change working directory (relative to the context / global `cwd` option); only available with glob pattern 172 | - `flatten` {Boolean} - using file's basename instead of folder hierarchy; default true; only available with glob pattern 173 | - `ignore` `{String|Array}` - glob pattern or array of glob patterns for matches to exclude 174 | 175 | For an glob example see example section below. 176 | 177 | ```javascript 178 | // simple version 179 | js: ["pth/to/file.js", { src: "pth/to/lib/file.js", dest: "lib/file.js" }]; 180 | // will be transformed to: 181 | js: { 182 | base: "js"; 183 | files: [ 184 | { src: "pth/to/file.js", dest: "file.js" }, 185 | { src: "pth/to/lib/file.js", dest: "lib/file.js" }, 186 | ]; 187 | } 188 | ``` 189 | 190 | ### Example 191 | 192 | ```javascript 193 | var clientlib = require("aem-clientlib-generator"); 194 | clientlib( 195 | [ 196 | { 197 | name: "test.base.apps.mainapp", 198 | // the name will be used as subfolder in clientlibs root and for the AEM repository node 199 | // in this example it creates: 200 | // the subfoler: path/to/clientlibs-root/test.base.apps.mainapp/ 201 | // repository node: path/to/clientlibs-root/test.base.apps.mainapp.json 202 | 203 | // new in AEM 6.2: configure the clientlib processor by yourself: 204 | // An example to disable minification for CSS: 205 | cssProcessor: ["default:none", "min:none"], 206 | 207 | // using google closure compiler for minification instead of YUI 208 | jsProcessor: ["default:none", "min:gcc;compilationLevel=whitespace"], 209 | 210 | // new in AEM 6.3: create clientLibs in /apps/myapp/clientlibs and proxy to /etc.clientlibs/myapp 211 | allowProxy: true, 212 | 213 | // will copy over the allowed properties and their values to the clientlib 214 | customProperties: [ 215 | "customProperty" 216 | ], 217 | customProperty: "customValue", 218 | 219 | // allow URL Fingerprinting via placeholder 220 | longCacheKey: "${project.version}-${buildNumber}", 221 | 222 | assets: { 223 | // creates the JS configuration file: 224 | // path/to/clientlibs-root/test.base.apps.mainapp/js.txt 225 | // which lists all JavaScript files from the ClientLib. 226 | // and copies all files into a js subfolder (default base): 227 | // path/to/clientlibs-root/test.base.apps.mainapp/js/ 228 | js: [ 229 | // file will be copied to: 230 | // path/to/clientlibs-root/test.base.apps.mainapp/js/app.js 231 | { src: "src/frontend/js/app.js", dest: "app.js" }, 232 | 233 | // file will be copied to: 234 | // path/to/clientlibs-root/test.base.apps.mainapp/js/libs/mylib.min.js 235 | { 236 | src: "src/frontend/js/libs/mylib.min.js", 237 | dest: "libs/mylib.min.js", 238 | }, 239 | 240 | // copy source map files as well 241 | { 242 | src: "src/frontend/js/libs/mylib.min.js.map", 243 | dest: "libs/mylib.min.js.map", 244 | }, 245 | ], 246 | 247 | // creates the CSS configuration file: 248 | // path/to/clientlibs-root/test.base.apps.mainapp/css.txt 249 | css: ["src/frontend/css/styling.css", "src/frontend/css/lib.css"], 250 | }, 251 | }, 252 | { 253 | name: "test.base.apps.secondapp", 254 | embed: [ 255 | "test.base.apps.thirdapp", // this clientlib will be auto embedded in AEM (kind of `merging`) 256 | ], 257 | dependencies: [ 258 | "test.base.apps.mainapp", // define clientlib dependency 259 | ], 260 | assets: { 261 | js: { 262 | base: "js", // by default the `base` is the asset key property 263 | files: [ 264 | { 265 | src: "src/frontend/secondapp/js/lib.js", 266 | dest: "secondapp-lib.js", 267 | }, 268 | ], 269 | }, 270 | 271 | // creates the CSS configuration file: 272 | // path/to/clientlibs-root/test.base.apps.secondapp/css.txt 273 | // that lists all CSS files from the ClientLib. 274 | // All files defined below will be copied into the defined base: 275 | // path/to/clientlibs-root/test.base.apps.secondapp/style/ 276 | css: { 277 | base: "style", // changes the `base` from `css` (default) to `style` 278 | files: ["src/frontend/secondapp/main.css"], 279 | }, 280 | resources: ["src/frontend/resources/template.html"], 281 | }, 282 | }, 283 | { 284 | name: "test.base.apps.thirdapp", 285 | assets: { 286 | // copy all files into the clientlib subfolder, because `base` is changed: 287 | // path/to/clientlibs-root/test.base.apps.thirdapp/ 288 | resources: { 289 | base: ".", // copy the file into `test.base.apps.thirdapp` (root) instead of `test.base.apps.thirdapp/resources` 290 | files: ["src/frontend/resources/notice.txt"], 291 | }, 292 | }, 293 | }, 294 | { 295 | name: "test.base.apps.fourth", 296 | assets: { 297 | js: { 298 | // "flatten" is true by default and using file's basename instead of path for destination 299 | // set to false to keep the folder hierarchy below "cwd" 300 | flatten: false, // remove this option if you like a flat list of files in your clientlib 301 | cwd: "src/frontend/js/", // change working directory (will be stripped from destination) 302 | files: [ 303 | "**/*.js", // match all js files recursively 304 | "**/*.js.map", 305 | ], 306 | }, 307 | css: [ 308 | // all css will copied to destination folder "style" (in base folder css) 309 | { src: "src/frontend/css/*.css", dest: "style/" }, 310 | 311 | // all css will copied to destination folder "vendor" (in base folder css) 312 | { src: "src/frontend/secondapp/*.css", dest: "vendor/" }, 313 | ], 314 | }, 315 | }, 316 | { 317 | name: "test.base.apps.myExistingAssetOrganization", 318 | outputPath: path.join(__dirname, "libs", "collectionOne"), 319 | assets: { 320 | // uses existing files at ./libs/collectionOne, since base is set to '.' 321 | js: { 322 | base: ".", // copy the file into `./libs/collectionOne` (outputPath) instead of `{path}/test.base.apps.myExistingAssetOrganization/js` 323 | files: ["libs/collectionOne/index.js"], 324 | }, 325 | }, 326 | }, 327 | ], 328 | { 329 | cwd: __dirname, // using folder of the file as current working directory 330 | clientLibRoot: path.join(__dirname, "path/to/clientlibs-root"), 331 | }, 332 | function () { 333 | console.log("clientlibs created"); 334 | } 335 | ); 336 | ``` 337 | 338 | ### Deploying to AEM: 339 | 340 | The generated client library can be deployed to AEM via [Sling Content Loading](https://sling.apache.org/documentation/bundles/content-loading-jcr-contentloader.html). Take a look at the [wcm.io Sample Application](https://github.com/wcm-io/wcm-io-samples/tree/develop/bundles/clientlibs). 341 | 342 | If you've switched the `serializationFormat` to "xml" you can deploy the client library as part of an AEM content package. 343 | -------------------------------------------------------------------------------- /test/clientlib.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 wcm.io and Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | import path from 'path'; 21 | import { fileURLToPath } from 'url'; 22 | const __filename = fileURLToPath(import.meta.url); 23 | const __dirname = path.dirname(__filename); 24 | 25 | export default { 26 | 27 | context: __dirname, 28 | clientLibRoot: path.resolve(__dirname, "result", "clientlibs-root"), 29 | 30 | libs: [{ 31 | name: "test.base.apps.mainapp", 32 | cssProcessor: ["default:none", "min:none"], // disable minification for CSS 33 | jsProcessor: ["default:none", "min:gcc"], // using google closure compiler instead of YUI, 34 | allowProxy: true, 35 | longCacheKey: "${project.version}-${buildNumber}", 36 | assets: { 37 | js: [{ 38 | src: "src/frontend/js/app.js", 39 | dest: "app.js" 40 | }, 41 | { 42 | src: "src/frontend/js/libs/mylib.min.js", 43 | dest: "libs/mylib.min.js" 44 | }, 45 | { 46 | src: "src/frontend/js/libs/mylib.min.js.map", 47 | dest: "libs/mylib.min.js.map" 48 | } 49 | ], 50 | css: [ 51 | "src/frontend/css/styling.css", 52 | "src/frontend/css/lib.css" 53 | ] 54 | } 55 | }, 56 | { 57 | name: "test.base.apps.secondapp", 58 | categories: [ 59 | "test.categorie.in.config" 60 | ], 61 | embed: [ 62 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 63 | ], 64 | dependencies: [ 65 | "test.base.apps.mainapp" // define clientlib dependency 66 | ], 67 | assets: { 68 | js: { 69 | base: "js", // by default the `base` is the asset key property 70 | files: [{ 71 | src: "src/frontend/secondapp/js/lib.js", 72 | dest: "secondapp-lib.js" 73 | }] 74 | }, 75 | css: { 76 | base: "style", // changes the `base` from `css` (default) to `style` 77 | files: [ 78 | "src/frontend/secondapp/main.css" 79 | ] 80 | }, 81 | resources: [ 82 | "src/frontend/resources/template.html" 83 | ] 84 | } 85 | }, 86 | { 87 | name: "test.base.apps.thirdapp", 88 | assets: { 89 | resources: { 90 | base: ".", // copy the file into `test.base.apps.thirdapp` (root) instead of `test.base.apps.thirdapp/resources` 91 | files: [ 92 | "src/frontend/resources/notice.txt" 93 | ] 94 | } 95 | } 96 | }, 97 | { 98 | name: "test.base.apps.fourth", 99 | assets: { 100 | js: { 101 | // "flatten" is true by default and using file's basename instead of path for destination 102 | // set to false to keep the folder hierarchy below "cwd" 103 | flatten: false, // remove this option if you like a flat list of files in your clientlib 104 | cwd: "src/frontend/js/", // change working directory (will be stripped from destination) 105 | files: [ 106 | "**/app.js", // this file should be included only once 107 | "**/*.js", // match all js files recursively 108 | "**/*.js.map" 109 | ] 110 | }, 111 | css: [ 112 | // all css will copied to destination folder "style" (in base folder css) 113 | { 114 | src: "src/frontend/css/*.css", 115 | dest: "style/" 116 | }, 117 | // all css will copied to destination folder "vendor" (in base folder css) 118 | { 119 | src: "src/frontend/secondapp/*.css", 120 | dest: "vendor/" 121 | } 122 | ] 123 | } 124 | }, 125 | { 126 | name: "test.base.apps.five", 127 | categories: [ 128 | "test.base.apps.five", 129 | "test.categorie.in.config" 130 | ], 131 | embed: [ 132 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 133 | ], 134 | dependencies: [ 135 | "test.base.apps.mainapp" // define clientlib dependency 136 | ], 137 | assets: { 138 | js: { 139 | base: "js", // by default the `base` is the asset key property 140 | files: [{ 141 | src: "src/frontend/secondapp/js/lib.js", 142 | dest: "secondapp-lib.js" 143 | }] 144 | }, 145 | css: { 146 | base: "style", // changes the `base` from `css` (default) to `style` 147 | files: [ 148 | "src/frontend/secondapp/main.css" 149 | ] 150 | }, 151 | resources: [ 152 | "src/frontend/resources/template.html" 153 | ] 154 | } 155 | }, 156 | { 157 | name: "test.base.apps.serializationFormatXML", 158 | serializationFormat: "xml", 159 | allowProxy: true, 160 | categories: [ 161 | "test.base.apps.six", 162 | "test.categorie.in.config" 163 | ], 164 | embed: [ 165 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 166 | ], 167 | dependencies: "test.base.apps.mainapp", 168 | assets: { 169 | js: { 170 | base: "js", // by default the `base` is the asset key property 171 | files: [{ 172 | src: "src/frontend/secondapp/js/lib.js", 173 | dest: "secondapp-lib.js" 174 | }] 175 | }, 176 | css: { 177 | base: "style", // changes the `base` from `css` (default) to `style` 178 | files: [ 179 | "src/frontend/secondapp/main.css" 180 | ] 181 | }, 182 | resources: [ 183 | "src/frontend/resources/template.html" 184 | ] 185 | } 186 | }, 187 | { 188 | name: "test.base.apps.fourthWithOutputPath", 189 | outputPath: 'result/clientlibs-root/myPrestructuredLibrary', 190 | assets: { 191 | js: { 192 | // "flatten" is true by default and using file's basename instead of path for destination 193 | // set to false to keep the folder hierarchy below "cwd" 194 | flatten: false, // remove this option if you like a flat list of files in your clientlib 195 | cwd: "src/frontend/js/", // change working directory (will be stripped from destination) 196 | files: [ 197 | "**/*.js", // match all js files recursively 198 | "**/*.js.map" 199 | ] 200 | }, 201 | css: [ 202 | // all css will copied to destination folder "style" (in base folder css) 203 | { 204 | src: "src/frontend/css/*.css", 205 | dest: "style/" 206 | }, 207 | // all css will copied to destination folder "vendor" (in base folder css) 208 | { 209 | src: "src/frontend/secondapp/*.css", 210 | dest: "vendor/" 211 | } 212 | ] 213 | } 214 | }, 215 | { 216 | name: "test.base.apps.customProperties", 217 | serializationFormat: "xml", 218 | outputPath: "result/clientlibs-root/test.base.apps.customProperties", 219 | customProperties: [ 220 | "customProperty" 221 | ], 222 | customProperty: "customValue", 223 | allowProxy: true, 224 | categories: [ 225 | "test.base.apps.six", 226 | "test.categorie.in.config" 227 | ], 228 | embed: [ 229 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 230 | ], 231 | dependencies: "test.base.apps.mainapp", 232 | assets: { 233 | js: { 234 | base: "js", // by default the `base` is the asset key property 235 | files: [{ 236 | src: "src/frontend/secondapp/js/lib.js", 237 | dest: "secondapp-lib.js" 238 | }] 239 | }, 240 | css: { 241 | base: "style", // changes the `base` from `css` (default) to `style` 242 | files: [ 243 | "src/frontend/secondapp/main.css" 244 | ] 245 | }, 246 | resources: [ 247 | "src/frontend/resources/template.html" 248 | ] 249 | } 250 | }, 251 | { 252 | name: "test.base.apps.customPropertiesNotAllowed", 253 | serializationFormat: "xml", 254 | outputPath: "result/clientlibs-root/test.base.apps.customPropertiesNotAllowed", 255 | customProperty: "customValue", 256 | allowProxy: true, 257 | categories: [ 258 | "test.base.apps.six", 259 | "test.categorie.in.config" 260 | ], 261 | embed: [ 262 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 263 | ], 264 | dependencies: "test.base.apps.mainapp", 265 | assets: { 266 | js: { 267 | base: "js", // by default the `base` is the asset key property 268 | files: [{ 269 | src: "src/frontend/secondapp/js/lib.js", 270 | dest: "secondapp-lib.js" 271 | }] 272 | }, 273 | css: { 274 | base: "style", // changes the `base` from `css` (default) to `style` 275 | files: [ 276 | "src/frontend/secondapp/main.css" 277 | ] 278 | }, 279 | resources: [ 280 | "src/frontend/resources/template.html" 281 | ] 282 | } 283 | }, 284 | { 285 | name: "test.base.apps.serializationFormatXMLCustomOutput", 286 | serializationFormat: "xml", 287 | outputPath: 'result/clientlibs-root/redirectOutputTestWithXML', 288 | allowProxy: true, 289 | categories: [ 290 | "test.base.apps.six", 291 | "test.categorie.in.config" 292 | ], 293 | embed: [ 294 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 295 | ], 296 | dependencies: "test.base.apps.mainapp", 297 | assets: { 298 | js: { 299 | base: "js", // by default the `base` is the asset key property 300 | files: [{ 301 | src: "src/frontend/secondapp/js/lib.js", 302 | dest: "secondapp-lib.js" 303 | }] 304 | }, 305 | css: { 306 | base: "style", // changes the `base` from `css` (default) to `style` 307 | files: [ 308 | "src/frontend/secondapp/main.css" 309 | ] 310 | }, 311 | resources: [ 312 | "src/frontend/resources/template.html" 313 | ] 314 | } 315 | }, 316 | { 317 | name: "test.base.apps.serializationFormatSlingXML", 318 | serializationFormat: "slingxml", 319 | allowProxy: true, 320 | longCacheKey: "${project.version}-${buildNumber}", 321 | categories: [ 322 | "test.base.apps.six", 323 | "test.categorie.in.config" 324 | ], 325 | embed: [ 326 | "test.base.apps.thirdapp" // this clientlib will be auto embedded in AEM (kind of `merging`) 327 | ], 328 | dependencies: [ 329 | "test.base.apps.mainapp" 330 | ], 331 | assets: { 332 | js: { 333 | base: "js", // by default the `base` is the asset key property 334 | files: [{ 335 | src: "src/frontend/secondapp/js/lib.js", 336 | dest: "secondapp-lib.js" 337 | }] 338 | }, 339 | css: { 340 | base: "style", // changes the `base` from `css` (default) to `style` 341 | files: [ 342 | "src/frontend/secondapp/main.css" 343 | ] 344 | }, 345 | resources: [ 346 | "src/frontend/resources/template.html" 347 | ] 348 | } 349 | }, 350 | { 351 | name: "test.base.apps.ignoreOption", 352 | assets: { 353 | js: { 354 | cwd: "src/frontend/js", 355 | flatten: false, 356 | files: ["**/*"], 357 | ignore: ["**/*.min.js", "**/*.min.js.map"] 358 | } 359 | } 360 | }, 361 | { 362 | // client lib with a combination of .css and .less files 363 | name: "test.base.apps.withLessFiles", 364 | assets: { 365 | css: [ 366 | "src/frontend/css/grid.less", 367 | "src/frontend/css/styling.css", 368 | "src/frontend/css/lib.css", 369 | ] 370 | } 371 | } 372 | ] 373 | }; 374 | -------------------------------------------------------------------------------- /lib/clientlib.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 wcm.io and Contributors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | "use strict"; 19 | 20 | import async from "async"; 21 | import path from "path"; 22 | import _ from "lodash"; 23 | import fs from "fs"; 24 | import fse from "fs-extra"; 25 | import glob from "glob"; 26 | 27 | /** 28 | * JSON serialization format 29 | * 30 | * @type {string} 31 | */ 32 | var SERIALIZATION_FORMAT_JSON = "json"; 33 | 34 | /** 35 | * XML serialization format for File Vault 36 | * 37 | * @type {string} 38 | */ 39 | var SERIALIZATION_FORMAT_XML = "xml"; 40 | 41 | /** 42 | * XML serialization format for Sling Initial Content 43 | * 44 | * @type {string} 45 | */ 46 | var SERIALIZATION_FORMAT_SLING_XML = "slingxml"; 47 | 48 | /** 49 | * List of fields to be evaluated for being added to the {@code cq:ClientLibraryFolder} file descriptor 50 | * @type {String[]} 51 | */ 52 | var defaultClientLibDirectoryFields = ["embed", "dependencies", "cssProcessor", "jsProcessor", "allowProxy", "longCacheKey", "replaces", "disableIfReplacing", "guideComponentType"]; 53 | var clientLibDirectoryFields = []; 54 | 55 | /** 56 | * List of source file extensions which AEM is able to merge and provide as `.js` or `.css` client-side library 57 | * @type {Object} 58 | */ 59 | var ALLOWED_EXTENSIONS = { 60 | css: [".css", ".less"], 61 | js: [".js"] 62 | } 63 | 64 | /** 65 | * @typedef {Object} ClientLibItem 66 | * @property {String} path - Clientlib root path (optional if `options.clientLibRoot` is set) 67 | * @property {String} name - Clientlib name 68 | * @property {String} [serializationFormat=json] - Type of the target archive for which the resources must be generated [json|xml|slingxml] (optional, default=json) 69 | * @property {boolean} [allowProxy] - Is the Clientlib meant to be used as a proxy 70 | * @property {Array} [embed] - other Clientlib names that should be embedded 71 | * @property {Array} [dependencies] - other Clientlib names that should be included 72 | * @property {Array} [categories] - to set a category for the clientLib (optional), ovrrides the default that uses the name as category 73 | * @property {Array} [customProperties] - by default only a set of known properties will be copied over the clientlib, using this field custom properties can be added 74 | * @property {Array} [cssProcessor] - Clientlib processor specification for CSS 75 | * @property {Array} [jsProcessor] - Clientlib processor specification for JS 76 | * @property {Array} assets - content that should be copied to the clientlib folder, more details below 77 | * @property {String} guideComponentType - property added for adaptive forms 78 | 79 | */ 80 | 81 | /** 82 | * Check if the given file exists 83 | * @param file 84 | * @returns {boolean} 85 | */ 86 | function fileExists(file) { 87 | try { 88 | fs.accessSync(file); 89 | return true; 90 | } catch (e) { 91 | return false; 92 | } 93 | } 94 | 95 | /** 96 | * Removes clientlib folder and configuration file (JSON) for the given 97 | * clientlib item. 98 | * @param {ClientLibItem} item - clientlib properties 99 | * @param {Object} [options] - further options 100 | * @param {Function} done - callback to be invoked after 101 | */ 102 | function removeClientLib(item, options, done) { 103 | var configJson = path.join(item.path, item.name + ".json"); 104 | var clientLibPath = path.join(item.path, item.name); 105 | var files = []; 106 | 107 | if (_.isFunction(options)) { 108 | done = options; 109 | options = {}; 110 | } 111 | if (fileExists(configJson)) { 112 | files.push(configJson); 113 | } 114 | if (fileExists(clientLibPath)) { 115 | files.push(clientLibPath); 116 | } 117 | 118 | if (files.length === 0) { 119 | return done(); 120 | } 121 | 122 | options.verbose && console.log("remove clientlib from " + clientLibPath); 123 | if (options.dry) { 124 | return done(); 125 | } 126 | async.eachSeries(files, function (file, doneClean) { 127 | fse.remove(file, doneClean); 128 | }, done); 129 | } 130 | 131 | /** 132 | * Write the clientlib asset TXT file (js or css) that describes the 133 | * base and contains all resource paths. 134 | * @param {String} clientLibPath - path to the clientlib folder 135 | * @param {Object} asset - asset object 136 | */ 137 | function writeAssetTxt(clientLibPath, asset, options) { 138 | 139 | if (!asset || !asset.type || !_.isArray(asset.files)) { 140 | return; 141 | } 142 | var outputFile = path.join(clientLibPath, asset.type + ".txt"); 143 | var basePath = path.posix.join(clientLibPath, asset.base); 144 | 145 | // determines file path relative to the base 146 | var filenames = []; 147 | 148 | options.verbose && console.log("write clientlib asset txt file (type: " + asset.type + "): " + outputFile); 149 | 150 | asset.files.forEach(function (file) { 151 | 152 | // inject only files that correspondents to the asset type 153 | if (ALLOWED_EXTENSIONS[asset.type].indexOf(path.extname(file.dest)) !== -1) { 154 | var rel = path.posix.relative(basePath, file.dest); 155 | filenames.push(rel); 156 | } 157 | }); 158 | 159 | var content = "#base=" + asset.base + "\n\n" + filenames.join("\n"); 160 | content.trim(); 161 | 162 | if (!options.dry) { 163 | fs.writeFileSync(outputFile, content); 164 | } 165 | } 166 | 167 | /** 168 | * Write a configuration JSON file for a clientlib 169 | * with the given properties in `item` 170 | * @param {ClientLibItem} item - clientlib configuration properties 171 | * @param {Array} properties - sorted list of properties to write 172 | * @param {Object} options - further options 173 | */ 174 | function writeClientLibJson(item, properties, options) { 175 | var content = { 176 | 'jcr:primaryType': 'cq:ClientLibraryFolder' 177 | }; 178 | 179 | properties.forEach(function (property) { 180 | content[property.key] = property.value; 181 | }); 182 | 183 | var jsonFile = path.join(item.path, item.name + ".json"); 184 | options.verbose && console.log("write clientlib json file: " + jsonFile); 185 | if (!options.dry) { 186 | fse.writeJsonSync(jsonFile, content, {spaces: 2}); 187 | } 188 | } 189 | 190 | /** 191 | * Write a configuration FileVault XML file for a clientlib 192 | * with the given properties in `item` 193 | * @param {ClientLibItem} item - clientlib configuration properties 194 | * @param {Array} properties - sorted list of properties to write 195 | * @param {Object} options - further options 196 | */ 197 | function writeClientLibXml(item, properties, options) { 198 | var content = '' + 199 | '\n} properties - sorted list of properties to write 231 | * @param {Object} options - further options 232 | */ 233 | function writeClientLibSlingXml(item, properties, options) { 234 | var content = '' + 235 | '\n' + 236 | '\n ' + item.name + '' + 237 | '\n cq:ClientLibraryFolder'; 238 | 239 | properties.forEach(function (property) { 240 | content += '\n \n ' + property.key + ''; 241 | if (typeof property.value === 'boolean') { 242 | // Boolean value 243 | content += 244 | '\n ' + property.value + '' + 245 | '\n Boolean'; 246 | } else if (Array.isArray(property.value)) { 247 | // Array of strings 248 | content += '\n '; 249 | property.value.forEach(value => { 250 | content += '\n ' + value + ''; 251 | }); 252 | content += '\n \n String'; 253 | } else if (typeof property.value === 'string') { 254 | // String value 255 | content += 256 | '\n ' + property.value + '' + 257 | '\n String'; 258 | } 259 | content += '\n '; 260 | }); 261 | content += '\n\n' 262 | 263 | var contentXml = getXmlOutputFile(item, SERIALIZATION_FORMAT_SLING_XML); 264 | 265 | options.verbose && console.log("write clientlib Sling-Initial-Content XML file: " + contentXml); 266 | 267 | if (!options.dry) { 268 | fse.writeFileSync(contentXml, content); 269 | } 270 | } 271 | 272 | /** 273 | * Get the output file name and path for the specified XML serialization format 274 | * @param {ClientLibItem} item - clientlib configuration properties 275 | * @param {String} serializationFormat serialization format (xml|slingxml) 276 | */ 277 | function getXmlOutputFile(item, serializationFormat) { 278 | 279 | // Sling initial content: .xml 280 | if (serializationFormat === SERIALIZATION_FORMAT_SLING_XML) { 281 | return item.outputPath || path.join(item.path, item.name + ".xml") 282 | } 283 | 284 | // FileVault: a folder with a .content.xml file in it 285 | var outputPath = item.outputPath || path.join(item.path, item.name); 286 | return path.join(outputPath + "/.content.xml"); 287 | } 288 | 289 | /** 290 | * Iterate through the given array of clientlib configuration objects and 291 | * process them asynchronously. 292 | * @param {Array} itemList - array of clientlib configuration items 293 | * @param {Object} [options] - global configuration options 294 | * @param {Function} done - to be called if everything is done 295 | */ 296 | function start(itemList, options, done) { 297 | 298 | if (_.isFunction(options)) { 299 | done = options; 300 | options = {}; 301 | } 302 | 303 | if (!_.isArray(itemList)) { 304 | itemList = [itemList]; 305 | } 306 | 307 | if (options.context || options.cwd) { 308 | options.cwd = options.context || options.cwd; 309 | process.chdir(options.cwd); 310 | } 311 | 312 | if (options.verbose) { 313 | console.log("\nstart aem-clientlib-generator"); 314 | console.log(" working directory: " + process.cwd()); 315 | } 316 | options.dry && console.log("\nDRY MODE - without write options!"); 317 | 318 | async.eachSeries(itemList, function (item, processItemDone) { 319 | processItem(item, options, processItemDone); 320 | }, done); 321 | } 322 | 323 | /** 324 | * Normalize different asset configuration options. 325 | * @param {String} clientLibPath - clientlib subfolder 326 | * @param {Object} assets - asset configuration object 327 | * @returns {*} 328 | */ 329 | function normalizeAssets(clientLibPath, assets) { 330 | 331 | var list = assets; 332 | 333 | // transform object to array 334 | if (!_.isArray(assets)) { 335 | list = []; 336 | _.keys(assets).forEach(function (assetKey) { 337 | var assetItem = assets[assetKey]; 338 | 339 | // check/transform short version 340 | if (_.isArray(assetItem)) { 341 | assetItem = { 342 | files: assetItem 343 | }; 344 | } 345 | if (!assetItem.base) { 346 | assetItem.base = assetKey; 347 | } 348 | assetItem.type = assetKey; 349 | list.push(assetItem); 350 | }); 351 | } 352 | 353 | // transform files to scr-dest mapping 354 | list.forEach(function (asset) { 355 | 356 | var mapping = []; 357 | var flatName = typeof asset.flatten !== "boolean" ? true : asset.flatten; 358 | var assetPath = path.posix.join(clientLibPath, asset.base); 359 | var globOptions = {}; 360 | if (asset.cwd) { 361 | globOptions.cwd = asset.cwd; 362 | } 363 | if (asset.ignore) { 364 | globOptions.ignore = asset.ignore; 365 | } 366 | 367 | asset.files.forEach(function (file) { 368 | var fileItem = file; 369 | 370 | // convert simple syntax to object 371 | if (_.isString(file)) { 372 | fileItem = { 373 | src: file 374 | }; 375 | } 376 | 377 | // no magic pattern -> default behaviour 378 | if (!glob.hasMagic(fileItem.src)) { 379 | 380 | // determine default dest 381 | if (!fileItem.dest) { 382 | fileItem.dest = path.posix.basename(file); 383 | } 384 | 385 | // generate full path 386 | fileItem.dest = path.posix.join(assetPath, fileItem.dest); 387 | mapping.push(fileItem); 388 | } 389 | 390 | // resolve magic pattern 391 | else { 392 | var files = glob.sync(fileItem.src, globOptions); 393 | var hasCwd = !!globOptions.cwd; 394 | var dest = fileItem.dest ? path.posix.join(assetPath, fileItem.dest) : assetPath; 395 | 396 | files.forEach(function (resolvedFile) { 397 | 398 | // check 'flatten' option -> strip dir name 399 | var destFile = flatName ? path.posix.basename(resolvedFile) : resolvedFile; 400 | 401 | var item = { 402 | src: resolvedFile, 403 | dest: path.posix.join(dest, destFile) 404 | }; 405 | 406 | // check "cwd" option -> rebuild path, because it was stripped by glob.sync() 407 | if (hasCwd) { 408 | item.src = path.posix.join(globOptions.cwd, resolvedFile); 409 | } 410 | 411 | mapping.push(item); 412 | }); 413 | } 414 | }); 415 | 416 | mapping = removeDuplicates(mapping, 'src'); 417 | 418 | asset.files = mapping; 419 | }); 420 | 421 | return list; 422 | } 423 | 424 | /** 425 | * Removes duplicates in array of Objects based on the provided key 426 | * From: https://firstclassjs.com/remove-duplicate-objects-from-javascript-array-how-to-performance-comparison/ 427 | * @param {Array} array - array of Objects that will be filtered 428 | * @param {String} key - key that will be used for filter comparison 429 | */ 430 | function removeDuplicates(array, key) { 431 | let lookup = new Set(); 432 | return array.filter(obj => !lookup.has(obj[key]) && lookup.add(obj[key])); 433 | } 434 | 435 | /** 436 | * Prepares a sorted list of all properties that should be written to the clientlib descriptor. 437 | */ 438 | function prepareSortedProperties(item) { 439 | var properties = []; 440 | 441 | // if categories is a config entry append the values to the array, else use item.name 442 | if (item.hasOwnProperty('categories')) { 443 | properties.push({key: 'categories', value: item['categories']}); 444 | } else { 445 | properties.push({key: 'categories', value: [item.name]}); 446 | } 447 | 448 | clientLibDirectoryFields.forEach(function (nodeKey) { 449 | if (item.hasOwnProperty(nodeKey)) { 450 | properties.push({key: nodeKey, value: item[nodeKey]}); 451 | } 452 | }); 453 | 454 | // sort properties by key 455 | properties.sort(function (a, b) { 456 | if (a.key < b.key) { 457 | return -1; 458 | } 459 | if (a.key > b.key) { 460 | return 1; 461 | } 462 | return 0; 463 | }); 464 | 465 | return properties; 466 | } 467 | 468 | /** 469 | * Process the given clientlib configuration object. 470 | * @param {ClientLibItem} item - clientlib configuration object 471 | * @param {Object} options - configuration options 472 | * @param {Function} processDone - to be called if everything is done 473 | */ 474 | function processItem(item, options, processDone) { 475 | 476 | if (!item.path) { 477 | item.path = options.clientLibRoot; 478 | } 479 | 480 | clientLibDirectoryFields.length = 0; 481 | clientLibDirectoryFields = defaultClientLibDirectoryFields.concat(item.customProperties); 482 | 483 | options.verbose && console.log("\n\nprocessing clientlib: " + item.name); 484 | 485 | // remove current files if exists 486 | removeClientLib(item, function (err) { 487 | 488 | var clientLibPath = item.outputPath || path.join(item.path, item.name); 489 | 490 | // create clientlib directory 491 | fse.mkdirsSync(clientLibPath); 492 | 493 | var serializationFormat = item.serializationFormat || SERIALIZATION_FORMAT_JSON; 494 | 495 | options.verbose && console.log("Write node configuration using serialization format: " + serializationFormat); 496 | 497 | var properties = prepareSortedProperties(item); 498 | if (serializationFormat === SERIALIZATION_FORMAT_JSON) { 499 | // write configuration JSON 500 | writeClientLibJson(item, properties, options); 501 | } else if (serializationFormat === SERIALIZATION_FORMAT_SLING_XML) { 502 | // write Sling-Initial-Content configuration 503 | writeClientLibSlingXml(item, properties, options); 504 | } else { 505 | // write FileVault XML configuration 506 | writeClientLibXml(item, properties, options); 507 | } 508 | 509 | var assetList = normalizeAssets(clientLibPath, item.assets); 510 | 511 | // iterate through assets 512 | async.eachSeries(assetList, function (asset, assetDone) { 513 | 514 | // write clientlib creator files 515 | if (asset.type === "js" || asset.type === "css") { 516 | options.verbose && console.log(""); 517 | writeAssetTxt(clientLibPath, asset, options); 518 | } 519 | 520 | // copy files for given asset 521 | async.eachSeries(asset.files, function (fileItem, copyDone) { 522 | if (fileItem.src == fileItem.dest) { 523 | options.verbose && console.log(`${fileItem.src} already in output directory`); 524 | return copyDone(); 525 | } 526 | options.verbose && console.log("copy:", fileItem.src, fileItem.dest); 527 | if (options.dry) { 528 | return copyDone(); 529 | } 530 | 531 | // create directories separately or it will be copied recursively 532 | if (fs.lstatSync(fileItem.src).isDirectory()) { 533 | fs.mkdir(fileItem.dest, { recursive: true }, copyDone); 534 | } else { 535 | fse.copy(fileItem.src, fileItem.dest, copyDone); 536 | } 537 | }, assetDone); 538 | 539 | }, processDone); 540 | }); 541 | } 542 | 543 | export default start; 544 | 545 | export { 546 | removeClientLib, 547 | fileExists 548 | }; 549 | --------------------------------------------------------------------------------