@adobe/helix-cli
Version:
Project Helix CLI
115 lines (99 loc) • 3.88 kB
JavaScript
/*
* Copyright 2018 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
const Asset = require('parcel-bundler/src/Asset');
const fs = require('fs');
const path = require('path');
const logger = require('parcel-bundler/src/Logger');
const { SourceMapConsumer, SourceMapGenerator } = require('source-map');
const resolver = require('./resolver');
const DEFAULT_PIPELINE = '@adobe/helix-pipeline/src/defaults/default.js';
const OUTPUT_TEMPLATE = path.resolve(__dirname, 'OutputTemplate.js');
/**
* Parcel Asset that handles the internal 'helix-js' type. It wraps the simple template transforming
* JS into an openwhisk action, using the {@code OUTPUT_TEMPLATE}.
*/
class HelixAsset extends Asset {
constructor(name, options) {
super(name, options);
this.type = 'js';
this.rendition = options.rendition;
this.sourceMap = this.rendition ? this.rendition.sourceMap : null;
}
async generate() {
const rootname = this.name.replace(/\.[^.]+$/, '');
const extension = resolver.extension(this.basename);
const pipe = this.getPreprocessor(
`${rootname}.pipe.js`,
`@adobe/helix-pipeline/src/defaults/${extension}.pipe.js`,
);
const pre = this.getPreprocessor(
`${rootname}.pre.js`,
`@adobe/helix-pipeline/src/defaults/${extension}.pre.js`,
);
let body = fs.readFileSync(OUTPUT_TEMPLATE, 'utf-8');
if (this.sourceMap) {
const index = body.search(/^\s*\/\/\s*CONTENTS\s*$/m);
const lineOffset = index !== -1 ? body.substring(0, index).match(/\n/g).length + 1 : 0;
this.sourceMap = await HelixAsset.shiftSourceMap(this.sourceMap, lineOffset);
}
body = body.replace(/^\s*\/\/\s*CONTENTS\s*$/m, `\n${this.contents}`);
body = body.replace(/MOD_PIPE/, pipe);
body = body.replace(/MOD_PRE/, pre);
return [{
type: 'helix-pre-js',
value: body,
sourceMap: this.sourceMap,
}];
}
getPreprocessor(name, fallback) {
if (fs.existsSync(name)) {
return path.relative(this.name, name).substr(1);
}
try {
if (require.resolve(fallback)) {
return fallback;
}
} catch (e) {
logger.log(`${fallback} cannot be found, using default pipeline`);
}
return DEFAULT_PIPELINE;
}
/**
* Shift the lines in a source map by some offset.
*
* @param {Object} sourceMap source map
* @param {Number} lineOffset line offset
* @returns shifted source map
*/
static async shiftSourceMap(sourceMap, lineOffset) {
const generator = new SourceMapGenerator({
file: sourceMap.file,
sourceRoot: sourceMap.sourceRoot,
});
// need to detour to string version. we can't use parcel's internal sourcemap here.
const srcMap = sourceMap.version ? sourceMap : sourceMap.stringify();
await SourceMapConsumer.with(srcMap, null, (consumer) => {
consumer.eachMapping((m) => {
generator.addMapping({
source: m.source,
name: m.name,
original: { line: m.originalLine, column: m.originalColumn },
generated: { line: m.generatedLine + lineOffset, column: m.generatedColumn },
});
});
});
const shiftedSourceMap = generator.toJSON();
shiftedSourceMap.sourcesContent = sourceMap.sourcesContent;
return shiftedSourceMap;
}
}
module.exports = HelixAsset;