From 5b2faa5943e9eff997da8dbe13e71fd4818fab76 Mon Sep 17 00:00:00 2001 From: Jan Dvorak Date: Sat, 1 Oct 2022 16:47:15 +0200 Subject: [PATCH 1/8] Move needed files for static-html into static-html-tools --- .../.npm/package/npm-shrinkwrap.json | 57 ++++-- packages/non-core/blaze | 2 +- .../promise/.npm/package/npm-shrinkwrap.json | 6 +- .../plugin/minifyStdJS/npm-shrinkwrap.json | 6 +- .../caching-html-compiler.js | 149 ++++++++++++++ .../static-html-tools/html-scanner-tests.js | 191 ++++++++++++++++++ packages/static-html-tools/html-scanner.js | 174 ++++++++++++++++ packages/static-html-tools/package.js | 36 ++++ .../static-html-tools/templating-tools.js | 3 + .../static-html-tools/throw-compile-error.js | 12 ++ packages/static-html/package.js | 7 +- packages/static-html/static-html.js | 12 +- 12 files changed, 622 insertions(+), 33 deletions(-) create mode 100644 packages/static-html-tools/caching-html-compiler.js create mode 100644 packages/static-html-tools/html-scanner-tests.js create mode 100644 packages/static-html-tools/html-scanner.js create mode 100644 packages/static-html-tools/package.js create mode 100644 packages/static-html-tools/templating-tools.js create mode 100644 packages/static-html-tools/throw-compile-error.js diff --git a/packages/minifier-js/.npm/package/npm-shrinkwrap.json b/packages/minifier-js/.npm/package/npm-shrinkwrap.json index a44b80076e..1b657072a1 100644 --- a/packages/minifier-js/.npm/package/npm-shrinkwrap.json +++ b/packages/minifier-js/.npm/package/npm-shrinkwrap.json @@ -1,10 +1,40 @@ { "lockfileVersion": 1, "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==" + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", + "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==" + }, "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" }, "buffer-from": { "version": "1.1.2", @@ -17,26 +47,19 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==" }, "terser": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", - "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==" + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==" } } } diff --git a/packages/non-core/blaze b/packages/non-core/blaze index c856c6604b..3ca48aa858 160000 --- a/packages/non-core/blaze +++ b/packages/non-core/blaze @@ -1 +1 @@ -Subproject commit c856c6604b6e54b9a8fe87cd941a8bd660fd7e4f +Subproject commit 3ca48aa858bf8aa4297307b1c9d5441315ae1d65 diff --git a/packages/promise/.npm/package/npm-shrinkwrap.json b/packages/promise/.npm/package/npm-shrinkwrap.json index 1fc0ce2f37..28c929e19b 100644 --- a/packages/promise/.npm/package/npm-shrinkwrap.json +++ b/packages/promise/.npm/package/npm-shrinkwrap.json @@ -7,9 +7,9 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "meteor-promise": { - "version": "1.0.0-alpha.0", - "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-1.0.0-alpha.0.tgz", - "integrity": "sha512-f0WbzHSkAqzaQW+LSVhj/XES9dnxNqiKj/qd18Dj0Mt6znt0+f+PYFEsO9PkLdHnIJzvX1iHDjfHvLzpTNPymw==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/meteor-promise/-/meteor-promise-0.9.0.tgz", + "integrity": "sha512-O1Fj1Oa5FfyIkAkDtZVnoYYEIC3miy7lvEeIQZVYunGSbOuivSbfAiPPsD+P45WNlcBALhUo94UzlHeIKBYNuQ==" }, "promise": { "version": "8.1.0", diff --git a/packages/standard-minifier-js/.npm/plugin/minifyStdJS/npm-shrinkwrap.json b/packages/standard-minifier-js/.npm/plugin/minifyStdJS/npm-shrinkwrap.json index 56735d318b..e0ab114049 100644 --- a/packages/standard-minifier-js/.npm/plugin/minifyStdJS/npm-shrinkwrap.json +++ b/packages/standard-minifier-js/.npm/plugin/minifyStdJS/npm-shrinkwrap.json @@ -2,9 +2,9 @@ "lockfileVersion": 1, "dependencies": { "@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==" + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==" }, "regenerator-runtime": { "version": "0.13.9", diff --git a/packages/static-html-tools/caching-html-compiler.js b/packages/static-html-tools/caching-html-compiler.js new file mode 100644 index 0000000000..ae324df484 --- /dev/null +++ b/packages/static-html-tools/caching-html-compiler.js @@ -0,0 +1,149 @@ +import { CompileError } from './throw-compile-error'; +import isEmpty from 'lodash.isempty'; +import { CachingCompiler } from 'meteor/caching-compiler'; + +const path = Plugin.path; + +// The CompileResult type for this CachingCompiler is the return value of +// htmlScanner.scan: a {js, head, body, bodyAttrs} object. +export class CachingHtmlCompiler extends CachingCompiler { + /** + * Constructor for CachingHtmlCompiler + * @param {String} name The name of the compiler, printed in errors - + * should probably always be the same as the name of the build + * plugin/package + * @param {Function} tagScannerFunc Transforms a template file (commonly + * .html) into an array of Tags + * @param {Function} tagHandlerFunc Transforms an array of tags into a + * results object with js, body, head, and bodyAttrs properties + */ + constructor(name, tagScannerFunc, tagHandlerFunc) { + super({ + compilerName: name, + defaultCacheSize: 1024*1024*10, + }); + + this._bodyAttrInfo = null; + + this.tagScannerFunc = tagScannerFunc; + this.tagHandlerFunc = tagHandlerFunc; + } + + // Implements method from CachingCompilerBase + compileResultSize(compileResult) { + function lengthOrZero(field) { + return field ? field.length : 0; + } + return lengthOrZero(compileResult.head) + lengthOrZero(compileResult.body) + + lengthOrZero(compileResult.js); + } + + // Overrides method from CachingCompiler + processFilesForTarget(inputFiles) { + this._bodyAttrInfo = {}; + return super.processFilesForTarget(inputFiles); + } + + // Implements method from CachingCompilerBase + getCacheKey(inputFile) { + // Note: the path is only used for errors, so it doesn't have to be part + // of the cache key. + return [ + inputFile.getArch(), + inputFile.getSourceHash(), + inputFile.hmrAvailable && inputFile.hmrAvailable() + ]; + } + + // Implements method from CachingCompiler + compileOneFile(inputFile) { + const contents = inputFile.getContentsAsString(); + const inputPath = inputFile.getPathInPackage(); + try { + const tags = this.tagScannerFunc({ + sourceName: inputPath, + contents: contents, + tagNames: ["body", "head", "template"] + }); + + return this.tagHandlerFunc(tags, inputFile.hmrAvailable && inputFile.hmrAvailable()); + } catch (e) { + if (e instanceof CompileError) { + inputFile.error({ + message: e.message, + line: e.line + }); + return null; + } else { + throw e; + } + } + } + + // Implements method from CachingCompilerBase + addCompileResult(inputFile, compileResult) { + let allJavaScript = ""; + + if (compileResult.head) { + inputFile.addHtml({ section: "head", data: compileResult.head }); + } + + if (compileResult.body) { + inputFile.addHtml({ section: "body", data: compileResult.body }); + } + + if (compileResult.js) { + allJavaScript += compileResult.js; + } + + if (!isEmpty(compileResult.bodyAttrs)) { + Object.keys(compileResult.bodyAttrs).forEach((attr) => { + const value = compileResult.bodyAttrs[attr]; + if (this._bodyAttrInfo.hasOwnProperty(attr) && + this._bodyAttrInfo[attr].value !== value) { + // two conflicting attributes on tags in two different template + // files + inputFile.error({ + message: + ` declarations have conflicting values for the '${ attr }' ` + + `attribute in the following files: ` + + this._bodyAttrInfo[attr].inputFile.getPathInPackage() + + `, ${ inputFile.getPathInPackage() }` + }); + } else { + this._bodyAttrInfo[attr] = {inputFile, value}; + } + }); + + // Add JavaScript code to set attributes on body + allJavaScript += +`Meteor.startup(function() { + var attrs = ${JSON.stringify(compileResult.bodyAttrs)}; + for (var prop in attrs) { + document.body.setAttribute(prop, attrs[prop]); + } +}); +`; + } + + + if (allJavaScript) { + const filePath = inputFile.getPathInPackage(); + // XXX this path manipulation may be unnecessarily complex + let pathPart = path.dirname(filePath); + if (pathPart === '.') + pathPart = ''; + if (pathPart.length && pathPart !== path.sep) + pathPart = pathPart + path.sep; + const ext = path.extname(filePath); + const basename = path.basename(filePath, ext); + + // XXX generate a source map + + inputFile.addJavaScript({ + path: path.join(pathPart, "template." + basename + ".js"), + data: allJavaScript + }); + } + } +} diff --git a/packages/static-html-tools/html-scanner-tests.js b/packages/static-html-tools/html-scanner-tests.js new file mode 100644 index 0000000000..f7bdde10fd --- /dev/null +++ b/packages/static-html-tools/html-scanner-tests.js @@ -0,0 +1,191 @@ +import { TemplatingTools } from 'meteor/templating-tools'; + +Tinytest.add("templating-tools - html scanner", function (test) { + var testInString = function(actualStr, wantedContents) { + if (actualStr.indexOf(wantedContents) >= 0) + test.ok(); + else + test.fail("Expected "+JSON.stringify(wantedContents)+ + " in "+JSON.stringify(actualStr)); + }; + + var checkError = function(f, msgText, lineNum) { + try { + f(); + } catch (e) { + if (! e instanceof TemplatingTools.CompileError) { + throw e; + } + + if (e.line === lineNum) + test.ok(); + else + test.fail("Error should have been on line " + lineNum + ", not " + + e.line); + testInString(e.message, msgText); + return; + } + test.fail("Parse error didn't throw exception"); + }; + + // returns the appropriate code to put content in the body, + // where content is something simple like the string "Hello" + // (passed in as a source string including the quotes). + var simpleBody = function (content) { + return "\nTemplate.body.addContent((function() {\n var view = this;\n return " + content + ";\n}));\nMeteor.startup(Template.body.renderToDocument);\n"; + }; + + // arguments are quoted strings like '"hello"' + var simpleTemplate = function (templateName, content) { + // '"hello"' into '"Template.hello"' + var viewName = templateName.slice(0, 1) + 'Template.' + templateName.slice(1); + + return '\nTemplate.__checkName(' + templateName + ');\nTemplate[' + templateName + + '] = new Template(' + viewName + + ', (function() {\n var view = this;\n return ' + content + ';\n}));\n'; + }; + + var checkResults = function(results, expectJs, expectHead, expectBodyAttrs) { + test.equal(results.body, ''); + test.equal(results.js, expectJs || ''); + test.equal(results.head, expectHead || ''); + test.equal(results.bodyAttrs, expectBodyAttrs || {}); + }; + + function scanForTest(contents) { + const tags = TemplatingTools.scanHtmlForTags({ + sourceName: "", + contents: contents, + tagNames: ["body", "head", "template"] + }); + + return TemplatingTools.compileTagsWithSpacebars(tags); + } + + checkError(function() { + return scanForTest("asdf"); + }, "Expected one of: , ,