diff --git a/packages/configs/default/index.json b/packages/configs/default/index.json index d054784e9477..febd87924aad 100644 --- a/packages/configs/default/index.json +++ b/packages/configs/default/index.json @@ -39,6 +39,7 @@ "resolvers": ["@parcel/resolver-default"], "reporters": [ "@parcel/reporter-cli", + "@parcel/reporter-loc", "@parcel/reporter-dev-server", "@parcel/reporter-hmr-server" ] diff --git a/packages/configs/default/package.json b/packages/configs/default/package.json index 33e8a44381c4..b0d2dac801d8 100644 --- a/packages/configs/default/package.json +++ b/packages/configs/default/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@parcel/bundler-default": "^2.0.0-alpha.1.1", + "@parcel/reporter-loc": "^2.0.0-alpha.1", "@parcel/namer-default": "^2.0.0-alpha.1.1", "@parcel/optimizer-cssnano": "^2.0.0-alpha.1.1", "@parcel/optimizer-terser": "^2.0.0-alpha.1.1", diff --git a/packages/core/core/src/BundleGraph.js b/packages/core/core/src/BundleGraph.js index dcfc90f347b6..53e9f116ada7 100644 --- a/packages/core/core/src/BundleGraph.js +++ b/packages/core/core/src/BundleGraph.js @@ -104,12 +104,6 @@ export default class BundleGraph { removeAssetGraphFromBundle(asset: Asset, bundle: Bundle) { this._graph.removeEdge(bundle.id, asset.id); this._graph.traverse(node => { - if ( - node.id === 'd5717aaa06434ee15cd3350952c9075a' && - bundle.id === 'bundle:b62e2effd6611fc26da1cadc271ca02a' - ) { - debugger; - } if (node.type === 'asset' || node.type === 'dependency') { this._graph.removeEdge(bundle.id, node.id, 'contains'); } diff --git a/packages/core/core/src/BundlerRunner.js b/packages/core/core/src/BundlerRunner.js index ada441b6a74b..8f83add688c5 100644 --- a/packages/core/core/src/BundlerRunner.js +++ b/packages/core/core/src/BundlerRunner.js @@ -198,10 +198,6 @@ export default class BundlerRunner { runtimeAssets: Array ) { for (let {code, filePath, dependency, isEntry} of runtimeAssets) { - // if (dependency.sourceAssetId === '30c91c73800a5d29d80ac8294f7e5ebe') { - // debugger; - // } - let builder = new AssetGraphBuilder(); await builder.init({ options: this.options, diff --git a/packages/reporters/loc/package.json b/packages/reporters/loc/package.json new file mode 100644 index 000000000000..12eef1bfaee2 --- /dev/null +++ b/packages/reporters/loc/package.json @@ -0,0 +1,20 @@ +{ + "name": "@parcel/reporter-loc", + "version": "2.0.0-alpha.1", + "main": "src/LOCReporter.js", + "engines": { + "node": ">= 8.0.0", + "parcel": "^2.0.0-alpha.1" + }, + "scripts": { + "test": "echo this package has no tests yet", + "test-ci": "yarn test" + }, + "dependencies": { + "@parcel/logger": "^2.0.0-alpha.1", + "@parcel/plugin": "^2.0.0-alpha.1", + "@parcel/types": "^2.0.0-alpha.1", + "@parcel/utils": "^2.0.0-alpha.1", + "nullthrows": "^1.1.1" + } +} diff --git a/packages/reporters/loc/src/LOCReporter.js b/packages/reporters/loc/src/LOCReporter.js new file mode 100644 index 000000000000..bd40c99cb863 --- /dev/null +++ b/packages/reporters/loc/src/LOCReporter.js @@ -0,0 +1,35 @@ +// @flow strict-local + +import type {ParcelOptions, ReporterEvent} from '@parcel/types'; + +import {Reporter} from '@parcel/plugin'; +import Logger from '@parcel/logger'; +import lineCounter from './lineCounter'; + +const LOG_LEVELS = { + none: 0, + error: 1, + warn: 2, + info: 3, + progress: 3, + success: 3, + verbose: 4 +}; + +export default new Reporter({ + async report(event: ReporterEvent, options: ParcelOptions) { + let logLevelFilter = options.logLevel || 'info'; + + if ( + event.type !== 'buildSuccess' || + LOG_LEVELS[logLevelFilter] < LOG_LEVELS.info + ) { + return; + } + + event.bundleGraph.getBundles(); + Logger.info( + 'Number of lines: ' + (await lineCounter(event.bundleGraph.getBundles())) + ); + } +}); diff --git a/packages/reporters/loc/src/lineCounter.js b/packages/reporters/loc/src/lineCounter.js new file mode 100644 index 000000000000..a158e2d73a55 --- /dev/null +++ b/packages/reporters/loc/src/lineCounter.js @@ -0,0 +1,75 @@ +// @flow + +import type {Bundle} from '@parcel/types'; + +const path = require('path'); +const fs = require('fs'); +const {PromiseQueue} = require('@parcel/utils'); +const os = require('os'); +const util = require('util'); + +const exists = util.promisify(fs.exists); + +const runtimesPath = path.resolve('../../runtimes'); + +const lineCounter = async (bundles: Array) => { + let set = new Set(); + + for (let bundle of bundles) { + bundle.traverseAssets(asset => { + let {filePath} = asset; + + if (filePath != null && !filePath.startsWith(runtimesPath)) { + set.add(filePath); + } + }); + } + + let queue = new PromiseQueue({maxConcurrent: os.cpus().length}); + let lineCount = 0; + for (let assetPath of set) { + queue + .add(() => countLinesInFile(assetPath)) + .then(count => (lineCount += count)); + } + + await queue.run(); + return lineCount; +}; + +const NEWLINE_CHAR = 10; +const NULL_BYTE = 0; // Only appears in binary files +const countLinesInFile = async filePath => { + // Parcel sometimes assigns filePaths to assets that don't exist + if (!(await exists(filePath))) { + return 0; + } + + return new Promise((resolve, reject) => { + let lineCount = 0; + + let stream = fs + .createReadStream(filePath) + .on('data', (buf: Buffer) => { + let i = -1; + lineCount--; + + if (buf.includes(NULL_BYTE)) { + stream.destroy(); + resolve(0); + return; + } + + do { + i = buf.indexOf(NEWLINE_CHAR, i + 1); + lineCount++; + } while (i !== -1); + }) + .on('end', () => { + resolve(lineCount); + }) + .on('error', reject); + }); +}; + +export default lineCounter;