@stencil/core
Version:
A Compiler for Web Components and Progressive Web Apps
1,622 lines (1,556 loc) • 5.85 MB
JavaScript
/*!
Stencil Compiler v2.14.0 | MIT Licensed | https://stenciljs.com
*/
(function(exports) {
'use strict';
if (typeof globalThis === 'undefined') {
if (typeof self !== 'undefined') {
self.globalThis = self;
} else if (typeof window !== 'undefined') {
window.globalThis = window;
} else if (typeof global !== 'undefined') {
global.globalThis = global;
}
}
const Buffer = globalThis.Buffer || {};
const process = globalThis.process || {};
if (!process.argv) {
process.argv = [''];
}
let __cwd = '/';
if (!process.cwd) {
process.cwd = () => __cwd;
}
if (!process.chdir) {
process.chdir = (v) => __cwd = v;
}
if (!process.nextTick) {
const resolved = Promise.resolve();
process.nextTick = (cb) => resolved.then(cb);
}
if (!process.platform) {
process.platform = 'stencil';
}
if (!process.version) {
process.version = 'v12.0.0';
}
process.browser = !!globalThis.location;
// 'path' module extracted from Node.js v8.11.1 (only the posix part)
function assertPath(path) {
if (typeof path !== 'string') {
throw new TypeError('Path must be a string. Received ' + JSON.stringify(path));
}
}
// Resolves . and .. elements in a path with directory names
function normalizeStringPosix(path, allowAboveRoot) {
var res = '';
var lastSegmentLength = 0;
var lastSlash = -1;
var dots = 0;
var code;
for (var i = 0; i <= path.length; ++i) {
if (i < path.length)
code = path.charCodeAt(i);
else if (code === 47 /*/*/)
break;
else
code = 47 /*/*/;
if (code === 47 /*/*/) {
if (lastSlash === i - 1 || dots === 1) ; else if (lastSlash !== i - 1 && dots === 2) {
if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== 46 /*.*/ || res.charCodeAt(res.length - 2) !== 46 /*.*/) {
if (res.length > 2) {
var lastSlashIndex = res.lastIndexOf('/');
if (lastSlashIndex !== res.length - 1) {
if (lastSlashIndex === -1) {
res = '';
lastSegmentLength = 0;
} else {
res = res.slice(0, lastSlashIndex);
lastSegmentLength = res.length - 1 - res.lastIndexOf('/');
}
lastSlash = i;
dots = 0;
continue;
}
} else if (res.length === 2 || res.length === 1) {
res = '';
lastSegmentLength = 0;
lastSlash = i;
dots = 0;
continue;
}
}
if (allowAboveRoot) {
if (res.length > 0)
res += '/..';
else
res = '..';
lastSegmentLength = 2;
}
} else {
if (res.length > 0)
res += '/' + path.slice(lastSlash + 1, i);
else
res = path.slice(lastSlash + 1, i);
lastSegmentLength = i - lastSlash - 1;
}
lastSlash = i;
dots = 0;
} else if (code === 46 /*.*/ && dots !== -1) {
++dots;
} else {
dots = -1;
}
}
return res;
}
function _format(sep, pathObject) {
var dir = pathObject.dir || pathObject.root;
var base = pathObject.base || (pathObject.name || '') + (pathObject.ext || '');
if (!dir) {
return base;
}
if (dir === pathObject.root) {
return dir + base;
}
return dir + sep + base;
}
var posix$2 = {
// path.resolve([from ...], to)
resolve: function resolve() {
var resolvedPath = '';
var resolvedAbsolute = false;
var cwd;
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
var path;
if (i >= 0)
path = arguments[i];
else {
if (cwd === undefined)
cwd = process.cwd();
path = cwd;
}
assertPath(path);
// Skip empty entries
if (path.length === 0) {
continue;
}
resolvedPath = path + '/' + resolvedPath;
resolvedAbsolute = path.charCodeAt(0) === 47 /*/*/;
}
// At this point the path should be resolved to a full absolute path, but
// handle relative paths to be safe (might happen when process.cwd() fails)
// Normalize the path
resolvedPath = normalizeStringPosix(resolvedPath, !resolvedAbsolute);
if (resolvedAbsolute) {
if (resolvedPath.length > 0)
return '/' + resolvedPath;
else
return '/';
} else if (resolvedPath.length > 0) {
return resolvedPath;
} else {
return '.';
}
},
normalize: function normalize(path) {
assertPath(path);
if (path.length === 0) return '.';
var isAbsolute = path.charCodeAt(0) === 47 /*/*/;
var trailingSeparator = path.charCodeAt(path.length - 1) === 47 /*/*/;
// Normalize the path
path = normalizeStringPosix(path, !isAbsolute);
if (path.length === 0 && !isAbsolute) path = '.';
if (path.length > 0 && trailingSeparator) path += '/';
if (isAbsolute) return '/' + path;
return path;
},
isAbsolute: function isAbsolute(path) {
assertPath(path);
return path.length > 0 && path.charCodeAt(0) === 47 /*/*/;
},
join: function join() {
if (arguments.length === 0)
return '.';
var joined;
for (var i = 0; i < arguments.length; ++i) {
var arg = arguments[i];
assertPath(arg);
if (arg.length > 0) {
if (joined === undefined)
joined = arg;
else
joined += '/' + arg;
}
}
if (joined === undefined)
return '.';
return posix$2.normalize(joined);
},
relative: function relative(from, to) {
assertPath(from);
assertPath(to);
if (from === to) return '';
from = posix$2.resolve(from);
to = posix$2.resolve(to);
if (from === to) return '';
// Trim any leading backslashes
var fromStart = 1;
for (; fromStart < from.length; ++fromStart) {
if (from.charCodeAt(fromStart) !== 47 /*/*/)
break;
}
var fromEnd = from.length;
var fromLen = fromEnd - fromStart;
// Trim any leading backslashes
var toStart = 1;
for (; toStart < to.length; ++toStart) {
if (to.charCodeAt(toStart) !== 47 /*/*/)
break;
}
var toEnd = to.length;
var toLen = toEnd - toStart;
// Compare paths to find the longest common path from root
var length = fromLen < toLen ? fromLen : toLen;
var lastCommonSep = -1;
var i = 0;
for (; i <= length; ++i) {
if (i === length) {
if (toLen > length) {
if (to.charCodeAt(toStart + i) === 47 /*/*/) {
// We get here if `from` is the exact base path for `to`.
// For example: from='/foo/bar'; to='/foo/bar/baz'
return to.slice(toStart + i + 1);
} else if (i === 0) {
// We get here if `from` is the root
// For example: from='/'; to='/foo'
return to.slice(toStart + i);
}
} else if (fromLen > length) {
if (from.charCodeAt(fromStart + i) === 47 /*/*/) {
// We get here if `to` is the exact base path for `from`.
// For example: from='/foo/bar/baz'; to='/foo/bar'
lastCommonSep = i;
} else if (i === 0) {
// We get here if `to` is the root.
// For example: from='/foo'; to='/'
lastCommonSep = 0;
}
}
break;
}
var fromCode = from.charCodeAt(fromStart + i);
var toCode = to.charCodeAt(toStart + i);
if (fromCode !== toCode)
break;
else if (fromCode === 47 /*/*/)
lastCommonSep = i;
}
var out = '';
// Generate the relative path based on the path difference between `to`
// and `from`
for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
if (i === fromEnd || from.charCodeAt(i) === 47 /*/*/) {
if (out.length === 0)
out += '..';
else
out += '/..';
}
}
// Lastly, append the rest of the destination (`to`) path that comes after
// the common path parts
if (out.length > 0)
return out + to.slice(toStart + lastCommonSep);
else {
toStart += lastCommonSep;
if (to.charCodeAt(toStart) === 47 /*/*/)
++toStart;
return to.slice(toStart);
}
},
_makeLong: function _makeLong(path) {
return path;
},
dirname: function dirname(path) {
assertPath(path);
if (path.length === 0) return '.';
var code = path.charCodeAt(0);
var hasRoot = code === 47 /*/*/;
var end = -1;
var matchedSlash = true;
for (var i = path.length - 1; i >= 1; --i) {
code = path.charCodeAt(i);
if (code === 47 /*/*/) {
if (!matchedSlash) {
end = i;
break;
}
} else {
// We saw the first non-path separator
matchedSlash = false;
}
}
if (end === -1) return hasRoot ? '/' : '.';
if (hasRoot && end === 1) return '//';
return path.slice(0, end);
},
basename: function basename(path, ext) {
if (ext !== undefined && typeof ext !== 'string') throw new TypeError('"ext" argument must be a string');
assertPath(path);
var start = 0;
var end = -1;
var matchedSlash = true;
var i;
if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
if (ext.length === path.length && ext === path) return '';
var extIdx = ext.length - 1;
var firstNonSlashEnd = -1;
for (i = path.length - 1; i >= 0; --i) {
var code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
start = i + 1;
break;
}
} else {
if (firstNonSlashEnd === -1) {
// We saw the first non-path separator, remember this index in case
// we need it if the extension ends up not matching
matchedSlash = false;
firstNonSlashEnd = i + 1;
}
if (extIdx >= 0) {
// Try to match the explicit extension
if (code === ext.charCodeAt(extIdx)) {
if (--extIdx === -1) {
// We matched the extension, so mark this as the end of our path
// component
end = i;
}
} else {
// Extension does not match, so our result is the entire path
// component
extIdx = -1;
end = firstNonSlashEnd;
}
}
}
}
if (start === end) end = firstNonSlashEnd;else if (end === -1) end = path.length;
return path.slice(start, end);
} else {
for (i = path.length - 1; i >= 0; --i) {
if (path.charCodeAt(i) === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
start = i + 1;
break;
}
} else if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// path component
matchedSlash = false;
end = i + 1;
}
}
if (end === -1) return '';
return path.slice(start, end);
}
},
extname: function extname(path) {
assertPath(path);
var startDot = -1;
var startPart = 0;
var end = -1;
var matchedSlash = true;
// Track the state of characters (if any) we see before our first dot and
// after any path separator we find
var preDotState = 0;
for (var i = path.length - 1; i >= 0; --i) {
var code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
startPart = i + 1;
break;
}
continue;
}
if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// extension
matchedSlash = false;
end = i + 1;
}
if (code === 46 /*.*/) {
// If this is our first dot, mark it as the start of our extension
if (startDot === -1)
startDot = i;
else if (preDotState !== 1)
preDotState = 1;
} else if (startDot !== -1) {
// We saw a non-dot and non-path separator before our dot, so we should
// have a good chance at having a non-empty extension
preDotState = -1;
}
}
if (startDot === -1 || end === -1 ||
// We saw a non-dot character immediately before the dot
preDotState === 0 ||
// The (right-most) trimmed path component is exactly '..'
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
return '';
}
return path.slice(startDot, end);
},
format: function format(pathObject) {
if (pathObject === null || typeof pathObject !== 'object') {
throw new TypeError('The "pathObject" argument must be of type Object. Received type ' + typeof pathObject);
}
return _format('/', pathObject);
},
parse: function parse(path) {
assertPath(path);
var ret = { root: '', dir: '', base: '', ext: '', name: '' };
if (path.length === 0) return ret;
var code = path.charCodeAt(0);
var isAbsolute = code === 47 /*/*/;
var start;
if (isAbsolute) {
ret.root = '/';
start = 1;
} else {
start = 0;
}
var startDot = -1;
var startPart = 0;
var end = -1;
var matchedSlash = true;
var i = path.length - 1;
// Track the state of characters (if any) we see before our first dot and
// after any path separator we find
var preDotState = 0;
// Get non-dir info
for (; i >= start; --i) {
code = path.charCodeAt(i);
if (code === 47 /*/*/) {
// If we reached a path separator that was not part of a set of path
// separators at the end of the string, stop now
if (!matchedSlash) {
startPart = i + 1;
break;
}
continue;
}
if (end === -1) {
// We saw the first non-path separator, mark this as the end of our
// extension
matchedSlash = false;
end = i + 1;
}
if (code === 46 /*.*/) {
// If this is our first dot, mark it as the start of our extension
if (startDot === -1) startDot = i;else if (preDotState !== 1) preDotState = 1;
} else if (startDot !== -1) {
// We saw a non-dot and non-path separator before our dot, so we should
// have a good chance at having a non-empty extension
preDotState = -1;
}
}
if (startDot === -1 || end === -1 ||
// We saw a non-dot character immediately before the dot
preDotState === 0 ||
// The (right-most) trimmed path component is exactly '..'
preDotState === 1 && startDot === end - 1 && startDot === startPart + 1) {
if (end !== -1) {
if (startPart === 0 && isAbsolute) ret.base = ret.name = path.slice(1, end);else ret.base = ret.name = path.slice(startPart, end);
}
} else {
if (startPart === 0 && isAbsolute) {
ret.name = path.slice(1, startDot);
ret.base = path.slice(1, end);
} else {
ret.name = path.slice(startPart, startDot);
ret.base = path.slice(startPart, end);
}
ret.ext = path.slice(startDot, end);
}
if (startPart > 0) ret.dir = path.slice(0, startPart - 1);else if (isAbsolute) ret.dir = '/';
return ret;
},
sep: '/',
delimiter: ':',
win32: null,
posix: null
};
posix$2.posix = posix$2;
var pathBrowserify = posix$2;
const IS_NODE_ENV = typeof global !== 'undefined' &&
typeof require === 'function' &&
!!global.process &&
typeof __filename === 'string' &&
(!global.origin || typeof global.origin !== 'string');
const OS_PLATFORM = IS_NODE_ENV ? process.platform : '';
const IS_WINDOWS_ENV = OS_PLATFORM === 'win32';
const IS_CASE_SENSITIVE_FILE_NAMES = !IS_WINDOWS_ENV;
const IS_BROWSER_ENV = typeof location !== 'undefined' && typeof navigator !== 'undefined' && typeof XMLHttpRequest !== 'undefined';
const IS_WEB_WORKER_ENV = IS_BROWSER_ENV && typeof self !== 'undefined' && typeof self.importScripts === 'function';
const HAS_WEB_WORKER = IS_BROWSER_ENV && typeof Worker === 'function';
const IS_FETCH_ENV = typeof fetch === 'function';
const requireFunc = IS_NODE_ENV ? require : () => { };
const getCurrentDirectory = IS_NODE_ENV ? process.cwd : () => '/';
/**
* Default style mode id
*/
const DEFAULT_STYLE_MODE = '$';
/**
* File names and value
*/
const COLLECTION_MANIFEST_FILE_NAME = 'collection-manifest.json';
const formatComponentRuntimeMeta = (compilerMeta, includeMethods) => {
let flags = 0;
if (compilerMeta.encapsulation === 'shadow') {
flags |= 1 /* shadowDomEncapsulation */;
if (compilerMeta.shadowDelegatesFocus) {
flags |= 16 /* shadowDelegatesFocus */;
}
}
else if (compilerMeta.encapsulation === 'scoped') {
flags |= 2 /* scopedCssEncapsulation */;
}
if (compilerMeta.encapsulation !== 'shadow' && compilerMeta.htmlTagNames.includes('slot')) {
flags |= 4 /* hasSlotRelocation */;
}
if (compilerMeta.hasMode) {
flags |= 32 /* hasMode */;
}
const members = formatComponentRuntimeMembers(compilerMeta, includeMethods);
const hostListeners = formatHostListeners(compilerMeta);
return trimFalsy([
flags,
compilerMeta.tagName,
Object.keys(members).length > 0 ? members : undefined,
hostListeners.length > 0 ? hostListeners : undefined,
]);
};
const stringifyRuntimeData = (data) => {
const json = JSON.stringify(data);
if (json.length > 10000) {
// JSON metadata is big, JSON.parse() is faster
// https://twitter.com/mathias/status/1143551692732030979
return `JSON.parse(${JSON.stringify(json)})`;
}
return json;
};
const formatComponentRuntimeMembers = (compilerMeta, includeMethods = true) => {
return {
...formatPropertiesRuntimeMember(compilerMeta.properties),
...formatStatesRuntimeMember(compilerMeta.states),
...(includeMethods ? formatMethodsRuntimeMember(compilerMeta.methods) : {}),
};
};
const formatPropertiesRuntimeMember = (properties) => {
const runtimeMembers = {};
properties.forEach((member) => {
runtimeMembers[member.name] = trimFalsy([
/**
* [0] member type
*/
formatFlags(member),
formatAttrName(member),
]);
});
return runtimeMembers;
};
const formatFlags = (compilerProperty) => {
let type = formatPropType(compilerProperty.type);
if (compilerProperty.mutable) {
type |= 1024 /* Mutable */;
}
if (compilerProperty.reflect) {
type |= 512 /* ReflectAttr */;
}
return type;
};
const formatAttrName = (compilerProperty) => {
if (typeof compilerProperty.attribute === 'string') {
// string attr name means we should observe this attribute
if (compilerProperty.name === compilerProperty.attribute) {
// property name and attribute name are the exact same
// true value means to use the property name for the attribute name
return undefined;
}
// property name and attribute name are not the same
// so we need to return the actual string value
// example: "multiWord" !== "multi-word"
return compilerProperty.attribute;
}
// we shouldn't even observe an attribute for this property
return undefined;
};
const formatPropType = (type) => {
if (type === 'string') {
return 1 /* String */;
}
if (type === 'number') {
return 2 /* Number */;
}
if (type === 'boolean') {
return 4 /* Boolean */;
}
if (type === 'any') {
return 8 /* Any */;
}
return 16 /* Unknown */;
};
const formatStatesRuntimeMember = (states) => {
const runtimeMembers = {};
states.forEach((member) => {
runtimeMembers[member.name] = [
32 /* State */,
];
});
return runtimeMembers;
};
const formatMethodsRuntimeMember = (methods) => {
const runtimeMembers = {};
methods.forEach((member) => {
runtimeMembers[member.name] = [
64 /* Method */,
];
});
return runtimeMembers;
};
const formatHostListeners = (compilerMeta) => {
return compilerMeta.listeners.map((compilerListener) => {
const hostListener = [
computeListenerFlags(compilerListener),
compilerListener.name,
compilerListener.method,
];
return hostListener;
});
};
const computeListenerFlags = (listener) => {
let flags = 0;
if (listener.capture) {
flags |= 2 /* Capture */;
}
if (listener.passive) {
flags |= 1 /* Passive */;
}
switch (listener.target) {
case 'document':
flags |= 4 /* TargetDocument */;
break;
case 'window':
flags |= 8 /* TargetWindow */;
break;
case 'body':
flags |= 16 /* TargetBody */;
break;
case 'parent':
flags |= 32 /* TargetParent */;
break;
}
return flags;
};
const trimFalsy = (data) => {
const arr = data;
for (var i = arr.length - 1; i >= 0; i--) {
if (arr[i]) {
break;
}
// if falsy, safe to pop()
arr.pop();
}
return arr;
};
const toLowerCase = (str) => str.toLowerCase();
const toDashCase = (str) => toLowerCase(str
.replace(/([A-Z0-9])/g, (g) => ' ' + g[0])
.trim()
.replace(/ /g, '-'));
const dashToPascalCase$1 = (str) => toLowerCase(str)
.split('-')
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
.join('');
const toTitleCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
const noop$1 = () => {
/* noop*/
};
const sortBy = (array, prop) => {
return array.slice().sort((a, b) => {
const nameA = prop(a);
const nameB = prop(b);
if (nameA < nameB)
return -1;
if (nameA > nameB)
return 1;
return 0;
});
};
const flatOne = (array) => {
if (array.flat) {
return array.flat(1);
}
return array.reduce((result, item) => {
result.push(...item);
return result;
}, []);
};
const unique = (array, predicate = (i) => i) => {
const set = new Set();
return array.filter((item) => {
const key = predicate(item);
if (key == null) {
return true;
}
if (set.has(key)) {
return false;
}
set.add(key);
return true;
});
};
const fromEntries = (entries) => {
const object = {};
for (const [key, value] of entries) {
object[key] = value;
}
return object;
};
const pluck = (obj, keys) => {
return keys.reduce((final, key) => {
if (obj[key]) {
final[key] = obj[key];
}
return final;
}, {});
};
const isBoolean$1 = (v) => typeof v === 'boolean';
const isDefined = (v) => v !== null && v !== undefined;
const isFunction = (v) => typeof v === 'function';
const isNumber$1 = (v) => typeof v === 'number';
const isObject$4 = (val) => val != null && typeof val === 'object' && Array.isArray(val) === false;
const isString$1 = (v) => typeof v === 'string';
const isIterable = (v) => isDefined(v) && isFunction(v[Symbol.iterator]);
const isPromise = (v) => !!v && (typeof v === 'object' || typeof v === 'function') && typeof v.then === 'function';
const isGlob = (str) => {
const chars = { '{': '}', '(': ')', '[': ']' };
/* eslint-disable-next-line max-len */
const regex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/;
if (str === '') {
return false;
}
let match;
while ((match = regex.exec(str))) {
if (match[2])
return true;
let idx = match.index + match[0].length;
// if an open bracket/brace/paren is escaped,
// set the index to the next closing character
const open = match[1];
const close = open ? chars[open] : null;
if (open && close) {
const n = str.indexOf(close, idx);
if (n !== -1) {
idx = n + 1;
}
}
str = str.slice(idx);
}
return false;
};
/**
* Checks if the path is the OS root path, such as "/" or "C:\"
*/
const isRootPath = (p) => p === '/' || windowsPathRegex.test(p);
// https://github.com/nodejs/node/blob/5883a59b21a97e8b7339f435c977155a2c29ba8d/lib/path.js#L43
const windowsPathRegex = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/]+[^\\/]+)?[\\/]$/;
/**
* Iterate through a series of diagnostics to provide minor fix-ups for various edge cases, deduplicate messages, etc.
* @param compilerCtx the current compiler context
* @param diagnostics the diagnostics to normalize
* @returns the normalize documents
*/
const normalizeDiagnostics = (compilerCtx, diagnostics) => {
const normalizedErrors = [];
const normalizedOthers = [];
const dups = new Set();
for (let i = 0; i < diagnostics.length; i++) {
const d = normalizeDiagnostic(compilerCtx, diagnostics[i]);
const key = d.absFilePath + d.code + d.messageText + d.type;
if (dups.has(key)) {
continue;
}
dups.add(key);
const total = normalizedErrors.length + normalizedOthers.length;
if (d.level === 'error') {
normalizedErrors.push(d);
}
else if (total < MAX_ERRORS) {
normalizedOthers.push(d);
}
}
return [...normalizedErrors, ...normalizedOthers];
};
/**
* Perform post-processing on a `Diagnostic` to handle a few message edge cases, massaging error message text and
* updating build failure contexts
* @param compilerCtx the current compiler
* @param diagnostic the diagnostic to normalize
* @returns the altered diagnostic
*/
const normalizeDiagnostic = (compilerCtx, diagnostic) => {
if (diagnostic.messageText) {
if (typeof diagnostic.messageText.message === 'string') {
diagnostic.messageText = diagnostic.messageText.message;
}
else if (typeof diagnostic.messageText === 'string' && diagnostic.messageText.indexOf('Error: ') === 0) {
diagnostic.messageText = diagnostic.messageText.substr(7);
}
}
if (diagnostic.messageText) {
if (diagnostic.messageText.includes(`Cannot find name 'h'`)) {
diagnostic.header = `Missing "h" import for JSX types`;
diagnostic.messageText = `In order to load accurate JSX types for components, the "h" function must be imported from "@stencil/core" by each component using JSX. For example: import { Component, h } from '@stencil/core';`;
try {
const sourceText = compilerCtx.fs.readFileSync(diagnostic.absFilePath);
const srcLines = splitLineBreaks(sourceText);
for (let i = 0; i < srcLines.length; i++) {
const srcLine = srcLines[i];
if (srcLine.includes('@stencil/core')) {
const msgLines = [];
const beforeLineIndex = i - 1;
if (beforeLineIndex > -1) {
const beforeLine = {
lineIndex: beforeLineIndex,
lineNumber: beforeLineIndex + 1,
text: srcLines[beforeLineIndex],
errorCharStart: -1,
errorLength: -1,
};
msgLines.push(beforeLine);
}
const errorLine = {
lineIndex: i,
lineNumber: i + 1,
text: srcLine,
errorCharStart: 0,
errorLength: -1,
};
msgLines.push(errorLine);
diagnostic.lineNumber = errorLine.lineNumber;
diagnostic.columnNumber = srcLine.indexOf('}');
const afterLineIndex = i + 1;
if (afterLineIndex < srcLines.length) {
const afterLine = {
lineIndex: afterLineIndex,
lineNumber: afterLineIndex + 1,
text: srcLines[afterLineIndex],
errorCharStart: -1,
errorLength: -1,
};
msgLines.push(afterLine);
}
diagnostic.lines = msgLines;
break;
}
}
}
catch (e) { }
}
}
return diagnostic;
};
/**
* Split a corpus by newlines. Carriage returns are treated a newlines.
* @param sourceText the corpus to split
* @returns the split text
*/
const splitLineBreaks = (sourceText) => {
if (typeof sourceText !== 'string')
return [];
sourceText = sourceText.replace(/\\r/g, '\n');
return sourceText.split('\n');
};
const escapeHtml = (unsafe) => {
if (unsafe === undefined)
return 'undefined';
if (unsafe === null)
return 'null';
if (typeof unsafe !== 'string') {
unsafe = unsafe.toString();
}
return unsafe
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
};
const MAX_ERRORS = 25;
/**
* Builds a template `Diagnostic` entity for a build error. The created `Diagnostic` is returned, and have little
* detail attached to it regarding the specifics of the error - it is the responsibility of the caller of this method
* to attach the specifics of the error message.
*
* The created `Diagnostic` is pushed to the `diagnostics` argument as a side effect of calling this method.
*
* @param diagnostics the existing diagnostics that the created template `Diagnostic` should be added to
* @returns the created `Diagnostic`
*/
const buildError = (diagnostics) => {
const diagnostic = {
level: 'error',
type: 'build',
header: 'Build Error',
messageText: 'build error',
relFilePath: null,
absFilePath: null,
lines: [],
};
if (diagnostics) {
diagnostics.push(diagnostic);
}
return diagnostic;
};
/**
* Builds a template `Diagnostic` entity for a build warning. The created `Diagnostic` is returned, and have little
* detail attached to it regarding the specifics of the warning - it is the responsibility of the caller of this method
* to attach the specifics of the warning message.
*
* The created `Diagnostic` is pushed to the `diagnostics` argument as a side effect of calling this method.
*
* @param diagnostics the existing diagnostics that the created template `Diagnostic` should be added to
* @returns the created `Diagnostic`
*/
const buildWarn = (diagnostics) => {
const diagnostic = {
level: 'warn',
type: 'build',
header: 'Build Warn',
messageText: 'build warn',
relFilePath: null,
absFilePath: null,
lines: [],
};
diagnostics.push(diagnostic);
return diagnostic;
};
const buildJsonFileError = (compilerCtx, diagnostics, jsonFilePath, msg, pkgKey) => {
const err = buildError(diagnostics);
err.messageText = msg;
err.absFilePath = jsonFilePath;
if (typeof pkgKey === 'string') {
try {
const jsonStr = compilerCtx.fs.readFileSync(jsonFilePath);
const lines = jsonStr.replace(/\r/g, '\n').split('\n');
for (let i = 0; i < lines.length; i++) {
const txtLine = lines[i];
const txtIndex = txtLine.indexOf(pkgKey);
if (txtIndex > -1) {
const warnLine = {
lineIndex: i,
lineNumber: i + 1,
text: txtLine,
errorCharStart: txtIndex,
errorLength: pkgKey.length,
};
err.lineNumber = warnLine.lineNumber;
err.columnNumber = txtIndex + 1;
err.lines.push(warnLine);
if (i >= 0) {
const beforeWarnLine = {
lineIndex: warnLine.lineIndex - 1,
lineNumber: warnLine.lineNumber - 1,
text: lines[i - 1],
errorCharStart: -1,
errorLength: -1,
};
err.lines.unshift(beforeWarnLine);
}
if (i < lines.length) {
const afterWarnLine = {
lineIndex: warnLine.lineIndex + 1,
lineNumber: warnLine.lineNumber + 1,
text: lines[i + 1],
errorCharStart: -1,
errorLength: -1,
};
err.lines.push(afterWarnLine);
}
break;
}
}
}
catch (e) { }
}
return err;
};
/**
* Builds a diagnostic from an `Error`, appends it to the `diagnostics` parameter, and returns the created diagnostic
* @param diagnostics the series of diagnostics the newly created diagnostics should be added to
* @param err the error to derive information from in generating the diagnostic
* @param msg an optional message to use in place of `err` to generate the diagnostic
* @returns the generated diagnostic
*/
const catchError = (diagnostics, err, msg) => {
const diagnostic = {
level: 'error',
type: 'build',
header: 'Build Error',
messageText: 'build error',
relFilePath: null,
absFilePath: null,
lines: [],
};
if (isString$1(msg)) {
diagnostic.messageText = msg.length ? msg : 'UNKNOWN ERROR';
}
else if (err != null) {
if (err.stack != null) {
diagnostic.messageText = err.stack.toString();
}
else {
if (err.message != null) {
diagnostic.messageText = err.message.length ? err.message : 'UNKNOWN ERROR';
}
else {
diagnostic.messageText = err.toString();
}
}
}
if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
diagnostics.push(diagnostic);
}
return diagnostic;
};
/**
* Determine if the provided diagnostics have any build errors
* @param diagnostics the diagnostics to inspect
* @returns true if any of the diagnostics in the list provided are errors that did not occur at runtime. false
* otherwise.
*/
const hasError = (diagnostics) => {
if (diagnostics == null || diagnostics.length === 0) {
return false;
}
return diagnostics.some((d) => d.level === 'error' && d.type !== 'runtime');
};
/**
* Determine if the provided diagnostics have any warnings
* @param diagnostics the diagnostics to inspect
* @returns true if any of the diagnostics in the list provided are warnings. false otherwise.
*/
const hasWarning = (diagnostics) => {
if (diagnostics == null || diagnostics.length === 0) {
return false;
}
return diagnostics.some((d) => d.level === 'warn');
};
const shouldIgnoreError = (msg) => {
return msg === TASK_CANCELED_MSG;
};
const TASK_CANCELED_MSG = `task canceled`;
const loadRollupDiagnostics = (config, compilerCtx, buildCtx, rollupError) => {
const formattedCode = formatErrorCode(rollupError.code);
const diagnostic = {
level: 'error',
type: 'bundling',
language: 'javascript',
code: rollupError.code,
header: `Rollup${formattedCode.length > 0 ? ': ' + formattedCode : ''}`,
messageText: formattedCode,
relFilePath: null,
absFilePath: null,
lines: [],
};
if (config.logLevel === 'debug' && rollupError.stack) {
diagnostic.messageText = rollupError.stack;
}
else if (rollupError.message) {
diagnostic.messageText = rollupError.message;
}
if (rollupError.plugin) {
diagnostic.messageText += ` (plugin: ${rollupError.plugin}${rollupError.hook ? `, ${rollupError.hook}` : ''})`;
}
const loc = rollupError.loc;
if (loc != null) {
const srcFile = loc.file || rollupError.id;
if (isString$1(srcFile)) {
try {
const sourceText = compilerCtx.fs.readFileSync(srcFile);
if (sourceText) {
diagnostic.absFilePath = srcFile;
try {
const srcLines = splitLineBreaks(sourceText);
const errorLine = {
lineIndex: loc.line - 1,
lineNumber: loc.line,
text: srcLines[loc.line - 1],
errorCharStart: loc.column,
errorLength: 0,
};
diagnostic.lineNumber = errorLine.lineNumber;
diagnostic.columnNumber = errorLine.errorCharStart;
const highlightLine = errorLine.text.substr(loc.column);
for (let i = 0; i < highlightLine.length; i++) {
if (charBreak.has(highlightLine.charAt(i))) {
break;
}
errorLine.errorLength++;
}
diagnostic.lines.push(errorLine);
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
errorLine.errorLength = 1;
errorLine.errorCharStart--;
}
if (errorLine.lineIndex > 0) {
const previousLine = {
lineIndex: errorLine.lineIndex - 1,
lineNumber: errorLine.lineNumber - 1,
text: srcLines[errorLine.lineIndex - 1],
errorCharStart: -1,
errorLength: -1,
};
diagnostic.lines.unshift(previousLine);
}
if (errorLine.lineIndex + 1 < srcLines.length) {
const nextLine = {
lineIndex: errorLine.lineIndex + 1,
lineNumber: errorLine.lineNumber + 1,
text: srcLines[errorLine.lineIndex + 1],
errorCharStart: -1,
errorLength: -1,
};
diagnostic.lines.push(nextLine);
}
}
catch (e) {
diagnostic.messageText += `\nError parsing: ${diagnostic.absFilePath}, line: ${loc.line}, column: ${loc.column}`;
diagnostic.debugText = sourceText;
}
}
else if (typeof rollupError.frame === 'string') {
diagnostic.messageText += '\n' + rollupError.frame;
}
}
catch (e) { }
}
}
buildCtx.diagnostics.push(diagnostic);
};
const createOnWarnFn = (diagnostics, bundleModulesFiles) => {
const previousWarns = new Set();
return function onWarningMessage(warning) {
if (warning == null || ignoreWarnCodes.has(warning.code) || previousWarns.has(warning.message)) {
return;
}
previousWarns.add(warning.message);
let label = '';
if (bundleModulesFiles) {
label = bundleModulesFiles
.reduce((cmps, m) => {
cmps.push(...m.cmps);
return cmps;
}, [])
.join(', ')
.trim();
if (label.length) {
label += ': ';
}
}
const diagnostic = buildWarn(diagnostics);
diagnostic.header = `Bundling Warning ${warning.code}`;
diagnostic.messageText = label + (warning.message || warning);
};
};
const ignoreWarnCodes = new Set([
'THIS_IS_UNDEFINED',
'NON_EXISTENT_EXPORT',
'CIRCULAR_DEPENDENCY',
'EMPTY_BUNDLE',
'UNUSED_EXTERNAL_IMPORT',
]);
const charBreak = new Set([' ', '=', '.', ',', '?', ':', ';', '(', ')', '{', '}', '[', ']', '|', `'`, `"`, '`']);
const formatErrorCode = (errorCode) => {
if (typeof errorCode === 'string') {
return errorCode
.split('_')
.map((c) => {
return toTitleCase(c.toLowerCase());
})
.join(' ');
}
return (errorCode || '').trim();
};
/**
* Convert Windows backslash paths to slash paths: foo\\bar ➔ foo/bar
* Forward-slash paths can be used in Windows as long as they're not
* extended-length paths and don't contain any non-ascii characters.
* This was created since the path methods in Node.js outputs \\ paths on Windows.
*/
const normalizePath$1 = (path) => {
if (typeof path !== 'string') {
throw new Error(`invalid path to normalize`);
}
path = normalizeSlashes(path.trim());
const components = pathComponents(path, getRootLength(path));
const reducedComponents = reducePathComponents(components);
const rootPart = reducedComponents[0];
const secondPart = reducedComponents[1];
const normalized = rootPart + reducedComponents.slice(1).join('/');
if (normalized === '') {
return '.';
}
if (rootPart === '' &&
secondPart &&
path.includes('/') &&
!secondPart.startsWith('.') &&
!secondPart.startsWith('@')) {
return './' + normalized;
}
return normalized;
};
const normalizeSlashes = (path) => path.replace(backslashRegExp, '/');
const altDirectorySeparator = '\\';
const urlSchemeSeparator = '://';
const backslashRegExp = /\\/g;
const reducePathComponents = (components) => {
if (!Array.isArray(components) || components.length === 0) {
return [];
}
const reduced = [components[0]];
for (let i = 1; i < components.length; i++) {
const component = components[i];
if (!component)
continue;
if (component === '.')
continue;
if (component === '..') {
if (reduced.length > 1) {
if (reduced[reduced.length - 1] !== '..') {
reduced.pop();
continue;
}
}
else if (reduced[0])
continue;
}
reduced.push(component);
}
return reduced;
};
const getRootLength = (path) => {
const rootLength = getEncodedRootLength(path);
return rootLength < 0 ? ~rootLength : rootLength;
};
const getEncodedRootLength = (path) => {
if (!path)
return 0;
const ch0 = path.charCodeAt(0);
// POSIX or UNC
if (ch0 === 47 /* slash */ || ch0 === 92 /* backslash */) {
if (path.charCodeAt(1) !== ch0)
return 1; // POSIX: "/" (or non-normalized "\")
const p1 = path.indexOf(ch0 === 47 /* slash */ ? '/' : altDirectorySeparator, 2);
if (p1 < 0)
return path.length; // UNC: "//server" or "\\server"
return p1 + 1; // UNC: "//server/" or "\\server\"
}
// DOS
if (isVolumeCharacter(ch0) && path.charCodeAt(1) === 58 /* colon */) {
const ch2 = path.charCodeAt(2);
if (ch2 === 47 /* slash */ || ch2 === 92 /* backslash */)
return 3; // DOS: "c:/" or "c:\"
if (path.length === 2)
return 2; // DOS: "c:" (but not "c:d")
}
// URL
const schemeEnd = path.indexOf(urlSchemeSeparator);
if (schemeEnd !== -1) {
const authorityStart = schemeEnd + urlSchemeSeparator.length;
const authorityEnd = path.indexOf('/', authorityStart);
if (authorityEnd !== -1) {
// URL: "file:///", "file://server/", "file://server/path"
// For local "file" URLs, include the leading DOS volume (if present).
// Per https://www.ietf.org/rfc/rfc1738.txt, a host of "" or "localhost" is a
// special case interpreted as "the machine from which the URL is being interpreted".
const scheme = path.slice(0, schemeEnd);
const authority = path.slice(authorityStart, authorityEnd);
if (scheme === 'file' &&
(authority === '' || authority === 'localhost') &&
isVolumeCharacter(path.charCodeAt(authorityEnd + 1))) {
const volumeSeparatorEnd = getFileUrlVolumeSeparatorEnd(path, authorityEnd + 2);
if (volumeSeparatorEnd !== -1) {
if (path.charCodeAt(volumeSeparatorEnd) === 47 /* slash */) {
// URL: "file:///c:/", "file://localhost/c:/", "file:///c%3a/", "file://localhost/c%3a/"
return ~(volumeSeparatorEnd + 1);
}
if (volumeSeparatorEnd === path.length) {
// URL: "file:///c:", "file://localhost/c:", "file:///c$3a", "file://localhost/c%3a"
// but not "file:///c:d" or "file:///c%3ad"
return ~volumeSeparatorEnd;
}
}
}
return ~(authorityEnd + 1); // URL: "file://server/", "http://server/"
}
return ~path.length; // URL: "file://server", "http://server"
}
// relative
return 0;
};
const isVolumeCharacter = (charCode) => (charCode >= 97 /* a */ && charCode <= 122 /* z */) ||
(charCode >= 65 /* A */ && charCode <= 90 /* Z */);
const getFileUrlVolumeSeparatorEnd = (url, start) => {
const ch0 = url.charCodeAt(start);
if (ch0 === 58 /* colon */)
return start + 1;
if (ch0 === 37 /* percent */ && url.charCodeAt(start + 1) === 51 /* _3 */) {
const ch2 = url.charCodeAt(start + 2);
if (ch2 === 97 /* a */ || ch2 === 65 /* A */)
return start + 3;
}
return -1;
};
const pathComponents = (path, rootLength) => {
const root = path.substring(0, rootLength);
const rest = path.substring(rootLength).split('/');
const restLen = rest.length;
if (restLen > 0 && !rest[restLen - 1]) {
rest.pop();
}
return [root, ...rest];
};
/**
* Same as normalizePath(), expect it'll also strip any querystrings
* from the path name. So /dir/file.css?tag=cmp-a becomes /dir/file.css
*/
const normalizeFsPath = (p) => normalizePath$1(p.split('?')[0].replace(/\0/g, ''));
const normalizeFsPathQuery = (importPath) => {
const pathParts = importPath.split('?');
const filePath = normalizePath$1(pathParts[0]);
const ext = filePath.split('.').pop().toLowerCase();
const params = pathParts.length > 1 ? new URLSearchParams(pathParts[1]) : null;
const format = params ? params.get('format') : null;
return {
filePath,
ext,
params,
format,
};
};
/**
* Augment a `Diagnostic` with information from a `Node` in the AST to provide richer error information
* @param d the diagnostic to augment
* @param node the node to augment with additional information
* @returns the augmented diagnostic
*/
const augmentDiagnosticWithNode = (d, node) => {
if (!node) {
return d;
}
const sourceFile = node.getSourceFile();
if (!sourceFile) {
return d;
}
d.absFilePath = normalizePath$1(sourceFile.fileName);
const sourceText = sourceFile.text;
const srcLines = splitLineBreaks(sourceText);
const start = node.getStart();
const end = node.getEnd();
const posStart = sourceFile.getLineAndCharacterOfPosition(start);
const errorLine = {
lineIndex: posStart.line,
lineNumber: posStart.line + 1,
text: srcLines[posStart.line],
errorCharStart: posStart.character,
errorLength: Math.max(end - start, 1),
};
// store metadata for line number and character index where the error occurred
d.lineNumber = errorLine.lineNumber;
d.columnNumber = errorLine.errorCharStart + 1;
d.lines.push(errorLine);
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
errorLine.errorLength = 1;
errorLine.errorCharStart--;
}
// if the error did not occur on the first line of the file, add metadata for the line of code preceding the line
// where the error was detected to provide the user with additional context
if (errorLine.lineIndex > 0) {
const previousLine = {
lineIndex: errorLine.lineIndex - 1,
lineNumber: errorLine.lineNumber - 1,
text: srcLines[errorLine.lineIndex - 1],
errorCharStart: -1,
errorLength: -1,
};
d.lines.unshift(previousLine);
}
// if the error did not occur on the last line of the file, add metadata for the line of code following the line
// where the error was detected to provide the user with additional context
if (errorLine.lineIndex + 1 < srcLines.length) {
const nextLine = {
lineIndex: errorLine.lineIndex + 1,
lineNumber: errorLine.lineNumber + 1,
text: srcLines[errorLine.lineIndex + 1],
errorCharStart: -1,
errorLength: -1,
};
d.lines.push(nextLine);
}
return d;
};
/**
* Ok, so formatting overkill, we know. But whatever, it makes for great
* error reporting within a terminal. So, yeah, let's code it up, shall we?
*/
const loadTypeScriptDiagnostics = (tsDiagnostics) => {
const diagnostics = [];
const maxErrors = Math.min(tsDiagnostics.length, 50);
for (let i = 0; i < maxErrors; i++) {
diagnostics.push(loadTypeScriptDiagnostic(tsDiagnostics[i]));
}
return diagnostics;
};
const loadTypeScriptDiagnostic = (tsDiagnostic) => {
const d = {
level: 'warn',
type: 'typescript',
language: 'typescript',
header: 'TypeScript',
code: tsDiagnostic.code.toString(),
messageText: flattenDiagnosticMessageText(tsDiagnostic, tsDiagnostic.messageText),
relFilePath: null,
absFilePath: null,
lines: [],
};
if (tsDiagnostic.category === 1) {
d.level = 'error';
}
if (tsDiagnostic.file) {
d.absFilePath = tsDiagnostic.file.fileName;
const sourceText = tsDiagnostic.file.text;
const srcLines = splitLineBreaks(sourceText);
const posData = tsDiagnostic.file.getLineAndCharacterOfPosition(tsDiagnostic.start);
const errorLine = {
lineIndex: posData.line,
lineNumber: posData.line + 1,
text: srcLines[posData.line],
errorCharStart: posData.character,
errorLength: Math.max(tsDiagnostic.length, 1),
};
d.lineNumber = errorLine.lineNumber;
d.columnNumber = errorLine.errorCharStart + 1;
d.lines.push(errorLine);
if (errorLine.errorLength === 0 && errorLine.errorCharStart > 0) {
errorLine.errorLength = 1;
errorLine.errorCharStart--;
}
if (errorLine.lineIndex > 0) {
const previousLine = {
lineIndex: errorLine.lineIndex - 1,
lineNumber: errorLine.lineNumber - 1,
text: srcLines[errorLine.lineIndex - 1],
errorCharStart: -1,
errorLength: -1,
};
d.lines.unshift(previousLine);
}
if (errorLine.lineIndex + 1 < srcLines.length) {
const nextLine = {
lineIndex: errorLine.lineIndex + 1,
lineNumber: errorLine.lineNumber + 1,
text: srcLines[errorLine.lineIndex + 1],
errorCharStart: -1,
errorLength: -1,
};
d.lines.push(nextLine);
}
}
return d;
};
const flattenDiagnosticMessageText = (tsDiagnostic, diag) => {
if (typeof diag === 'string') {
return diag;
}
else if (diag === undefined) {
return '';
}
const ignoreCodes = [];
const isStencilConfig = tsDiagnostic.file.fileName.includes('stencil.config');
if (isStencilConfig) {
ignoreCodes.push(2322);
}
let result = '';
if (!ignoreCodes.includes(diag.code)) {
result = diag.messageText;
if (isIterable(diag.next)) {
for (const kid of diag.next) {
result += flattenDiagnosticMessageText(tsDiagnostic, kid);
}
}
}
if (isStencilConfig) {
result = result.replace(`type 'StencilConfig'`, `Stencil Config`);
result = result.replace(`Object literal may only specify known properties, but `, ``);
result = result.replace(`Object literal may only specify known properties, and `, ``);
}
return result.trim();
};
const isRemoteUrl = (p) => {
if (isString$1(p)) {
p = p.toLowerCase();
return p.startsWith('https://') || p.startsWith('http://');
}
return false;
};
const createJsVarName = (fileName) => {
if (isString$1(fileName)) {
fileName = fileName.split('?')[0];
fileName = fileName.split('#')[0];
fileName = fileName.split('&')[0];
fileName = fileName.split('=')[0];
fileName = toDashCase(fileName);
fileName = fileName.replace(/[|;$%@"<>()+,.{}_\!\/\\]/g, '-');
fileName = dashToPascalCase$1(fileName);
if (fileName.length > 1) {
fileName = fileName[0].toLowerCase() + fileName.substr(1);
}
else {
fileName = fileName.toLowerCase();
}
if (fileName.length > 0 && !isNaN(fileName[0])) {
fileName = '_' + fileName;
}
}
return fileName;
};
const isDtsFile$1 = (filePath) => {
const parts = filePath.toLowerCase().split('.');
if (parts.length > 2) {
return parts[parts.length - 2] === 'd' && parts[parts.length - 1] === 'ts';
}
return false;
};
/**
* Generate the preamble to be placed atop the main file of the build
* @param config the Stencil configuration file
* @return the generated preamble
*/
const generatePreamble = (config) => {
const { preamble } = config;
if (!preamble) {
return '';
}
// generate the body of the JSDoc-style comment
const preambleComment = preamble.split('\n').map((l) => ` * ${l}`);
preambleComment.unshift(`/*!`);
preambleComme