/** * Check whether a component is external package, e.g. @ali/uxcore * @param path Component path */ export function isPackagePath(path: string): boolean { return !path.startsWith('.') && !path.startsWith('/'); } /** * Title cased string * @param s original string */ export function toTitleCase(s: string): string { return s .split(/[-_ .]+/) .map(token => token[0].toUpperCase() + token.substring(1)) .join(''); } /** * Make up an import name/tag for components * @param path Original path name */ export function generateComponentName(path: string): string { const parts = path.split('/'); let name = parts.pop(); if (name && /^index\./.test(name)) { name = parts.pop(); } return name ? toTitleCase(name) : 'Component'; } /** * normalizing import path for easier comparison */ export function getNormalizedImportPath(path: string): string { const segments = path.split('/'); let basename = segments.pop(); if (!basename) { return path; } const ignoredExtensions = ['.ts', '.js', '.tsx', '.jsx']; const extIndex = basename.lastIndexOf('.'); if (extIndex > -1) { const ext = basename.slice(extIndex); if (ignoredExtensions.includes(ext)) { basename = basename.slice(0, extIndex); } } if (basename !== 'index') { segments.push(basename); } return segments.join('/'); } /** * make a relative path * * @param toPath abolute path * @param fromPath absolute path */ export function makeRelativePath(toPath: string, fromPath: string) { // not a absolute path, eg. @ali/uxcore if (!toPath.startsWith('/')) { return toPath; } const toParts = toPath.split('/'); const fromParts = fromPath.split('/'); // find shared path header const length = Math.min(fromParts.length, toParts.length); let sharedUpTo = length; for (let i = 0; i < length; i++) { if (fromParts[i] !== toParts[i]) { sharedUpTo = i; break; } } // find how many levels to go up from // minus another 1 since we do not include the final const numGoUp = fromParts.length - sharedUpTo - 1; // generate final path let outputParts = []; if (numGoUp === 0) { // in the same dir outputParts.push('.'); } else { // needs to go up for (let i = 0; i < numGoUp; ++i) { outputParts.push('..'); } } outputParts = outputParts.concat(toParts.slice(sharedUpTo)); return outputParts.join('/'); } function normalizeArray(parts: string[], allowAboveRoot: boolean) { const res = []; for (let i = 0; i < parts.length; i++) { const p = parts[i]; // ignore empty parts if (!p || p === '.') { continue; } if (p === '..') { if (res.length && res[res.length - 1] !== '..') { res.pop(); } else if (allowAboveRoot) { res.push('..'); } } else { res.push(p); } } return res; } function normalize(path: string): string { const isAbsolute = path[0] === '/'; const segments = normalizeArray(path.split('/'), !isAbsolute); if (isAbsolute) { segments.unshift(''); } else if (segments.length < 1 || segments[0] !== '..') { segments.unshift('.'); } return segments.join('/'); } /** * Resolve component with absolute path to relative path * @param path absolute path of component from project */ export function resolveAbsoluatePath(path: string, base: string): string { if (!path.startsWith('.')) { // eg. /usr/path/to, @ali/button return path; } path = path.replace(/\\/g, '/'); if (base.slice(-1) !== '/') { base += '/'; } return normalize(base + path); } export function joinPath(...segments: string[]) { let path = ''; for (const seg of segments) { if (seg) { if (path === '') { path += seg; } else { path += '/' + seg; } } } return normalize(path); } export function removeVersion(path: string): string { if (path.lastIndexOf('@') > 0) { path = path.replace(/(@?[^@]+)(@[\w.-]+)(.+)/, '$1$3'); } return path; }