Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions packages/cli/bin/install-edition.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ const {
writeJsonAsync,
getJSONKey,
} = require('./utils');
const {
resolveFileInPackage,
resolveDirInPackage,
} = require('@pattern-lab/core/src/lib/resolver');

// https://github.com/TehShrike/deepmerge#overwrite-array
const overwriteMerge = (destinationArray, sourceArray, options) => sourceArray;
Expand All @@ -31,7 +35,7 @@ const installEdition = (edition, config, projectDir) => {
const sourceDir = config.paths.source.root;
yield checkAndInstallPackage(edition); // 1
yield copyAsync(
path.resolve('./node_modules', edition, 'source', '_meta'),
resolveDirInPackage(edition, 'source', '_meta'),
path.resolve(sourceDir, '_meta')
); // 2
pkg.dependencies = Object.assign(
Expand All @@ -45,16 +49,15 @@ const installEdition = (edition, config, projectDir) => {
// 4.1
case '@pattern-lab/edition-node-gulp': {
yield copyAsync(
path.resolve('./node_modules', edition, 'gulpfile.js'),
resolveFileInPackage(edition, 'gulpfile.js'),
path.resolve(sourceDir, '../', 'gulpfile.js')
);
break;
}
// 4.2
case '@pattern-lab/edition-node': {
const editionPath = path.resolve('./node_modules', edition);
const editionConfigPath = path.resolve(
editionPath,
const editionConfigPath = resolveFileInPackage(
edition,
'patternlab-config.json'
);

Expand All @@ -67,7 +70,7 @@ const installEdition = (edition, config, projectDir) => {
);

yield copyAsync(
path.join(editionPath, path.sep, 'helpers', path.sep, 'test.js'),
resolveFileInPackage(edition, 'helpers', 'test.js'),
path.resolve(sourceDir, '../', 'helpers/test.js')
);

Expand All @@ -76,9 +79,8 @@ const installEdition = (edition, config, projectDir) => {
}
// 4.3
case '@pattern-lab/edition-twig': {
const editionPath = path.resolve('./node_modules', edition);
const editionConfigPath = path.resolve(
editionPath,
const editionConfigPath = resolveFileInPackage(
edition,
'patternlab-config.json'
);
const editionConfig = require(editionConfigPath);
Expand All @@ -90,7 +92,7 @@ const installEdition = (edition, config, projectDir) => {
);

yield copyAsync(
path.resolve(editionPath, 'alter-twig.php'),
resolveFileInPackage(edition, 'alter-twig.php'),
path.resolve(sourceDir, '../', 'alter-twig.php')
);

Expand Down
10 changes: 3 additions & 7 deletions packages/cli/bin/install-plugin.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
'use strict';

const path = require('path');

const _ = require('lodash');

const checkAndInstallPackage = require('./utils').checkAndInstallPackage;
const wrapAsync = require('./utils').wrapAsync;
const { checkAndInstallPackage, wrapAsync } = require('./utils');
const { resolveFileInPackage } = require('@pattern-lab/core/src/lib/resolver');

const installPlugin = (plugin, config) =>
wrapAsync(function*() {
Expand All @@ -16,9 +14,7 @@ const installPlugin = (plugin, config) =>
_.set(config, `plugins[${name}]['initialized']`, false);

// Get the options from the plugin, if any
const pluginPathConfig = path.resolve(
path.join(process.cwd(), 'node_modules', name, 'config.json')
);
const pluginPathConfig = resolveFileInPackage(name, 'config.json');
try {
const pluginConfigJSON = require(pluginPathConfig);
if (!_.has(config.plugins[name].options)) {
Expand Down
9 changes: 6 additions & 3 deletions packages/cli/bin/install-starterkit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ const {
checkAndInstallPackage,
readJsonAsync,
} = require('./utils');
const {
resolveFileInPackage,
resolveDirInPackage,
} = require('@pattern-lab/core/src/lib/resolver');

const installStarterkit = (starterkit, config) =>
wrapAsync(function*() {
const sourceDir = config.paths.source.root;
const name = starterkit.value || starterkit;
yield checkAndInstallPackage(name);
const kitPath = path.resolve('./node_modules', name);
yield copyAsync(path.resolve(kitPath, 'dist'), path.resolve(sourceDir));
yield copyAsync(resolveDirInPackage(name, 'dist'), path.resolve(sourceDir));
let kitConfig;
const kitConfigPath = path.resolve(kitPath, 'patternlab-config.json');
const kitConfigPath = resolveFileInPackage(name, 'patternlab-config.json');
if (fs.existsSync(kitConfigPath)) {
kitConfig = yield readJsonAsync(kitConfigPath);
}
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/bin/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const path = require('path');
const chalk = require('chalk');
const EventEmitter = require('events').EventEmitter;
const hasYarn = require('has-yarn');
const { resolveFileInPackage } = require('@pattern-lab/core/src/lib/resolver');

/**
* @name log
Expand Down Expand Up @@ -124,7 +125,7 @@ const copyWithPattern = (cwd, pattern, dest) =>

/**
* @func fetchPackage
* @desc Fetches and saves packages from npm into node_modules and adds a reference in the package.json under dependencies
* @desc Fetches packages from an npm package registry and adds a reference in the package.json under dependencies
* @param {string} packageName - The package name
*/
const fetchPackage = packageName =>
Expand Down Expand Up @@ -193,7 +194,7 @@ const getJSONKey = (packageName, key, fileName = 'package.json') =>
wrapAsync(function*() {
yield checkAndInstallPackage(packageName);
const jsonData = yield fs.readJson(
path.resolve('node_modules', packageName, fileName)
resolveFileInPackage(packageName, fileName)
);
return jsonData[key];
});
Expand Down
1 change: 1 addition & 0 deletions packages/core/patternlab-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"uikits": [
{
"name": "uikit-workshop",
"package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
Expand Down
6 changes: 2 additions & 4 deletions packages/core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ const patternlab_module = function(config) {
},

/**
* Installs plugin already available via `node_modules/`
* Installs plugin already available as a package dependency
*
* @memberof patternlab
* @name installplugin
Expand All @@ -214,8 +214,6 @@ const patternlab_module = function(config) {
* @returns {void}
*/
installplugin: function(pluginName) {
//get the config
const configPath = path.resolve(process.cwd(), 'patternlab-config.json');
const plugin_manager = new pm();

plugin_manager.install_plugin(pluginName);
Expand All @@ -234,7 +232,7 @@ const patternlab_module = function(config) {
},

/**
* Loads starterkit already available via `node_modules/`
* Loads starterkit already available as a package dependency
*
* @memberof patternlab
* @name loadstarterkit
Expand Down
117 changes: 68 additions & 49 deletions packages/core/src/lib/loaduikits.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,91 +5,110 @@ const _ = require('lodash');

const logger = require('./log');

let findModules = require('./findModules'); //eslint-disable-line prefer-const
let fs = require('fs-extra'); // eslint-disable-line

const uiKitMatcher = /^uikit-(.*)$/;
const nodeModulesPath = path.join(process.cwd(), 'node_modules');

/**
* Given a path: return the uikit name if the path points to a valid uikit
* module directory, or false if it doesn't.
* @param filePath
* @returns UIKit name if exists or FALSE
*/
const isUIKitModule = filePath => {
const baseName = path.basename(filePath);
const engineMatch = baseName.match(uiKitMatcher);
const { resolvePackageFolder } = require('./resolver');

if (engineMatch) {
return engineMatch[1];
}
return false;
};
let fs = require('fs-extra'); // eslint-disable-line

const readModuleFile = (kit, subPath) => {
const readModuleFile = (uikitLocation, subPath) => {
return fs.readFileSync(
path.resolve(path.join(kit.modulePath, subPath)),
path.resolve(path.join(uikitLocation, subPath)),
'utf8'
);
};

/**
* Loads uikits, connecting configuration and installed modules
* [1] Looks in node_modules for uikits.
* [2] Filter out our uikit-polyfills package.
* [3] Only continue if uikit is enabled in patternlab-config.json
* [1] Lists the enabled uikits from patternlab-config.json
* [2] Try to resolve the location of the uikit in the package dependencies
* [3] Warn when the uikit couldn't be loaded
* [4] Reads files from uikit that apply to every template
* @param {object} patternlab
*/
module.exports = patternlab => {
const paths = patternlab.config.paths;

const uikits = findModules(nodeModulesPath, isUIKitModule) // [1]
.filter(kit => kit.name !== 'polyfills'); // [2]
uikits.forEach(kit => {
const configEntry = _.find(_.filter(patternlab.config.uikits, 'enabled'), {
name: `uikit-${kit.name}`,
}); // [3]

if (!configEntry) {
logger.warning(
`Could not find uikit with name uikit-${kit.name} defined within patternlab-config.json, or it is not enabled.`
);
return;
const uikitConfigs = _.filter(patternlab.config.uikits, 'enabled'); // [1]
uikitConfigs.forEach(uikitConfig => {
let uikitLocation = null;
if ('package' in uikitConfig) {
try {
uikitLocation = resolvePackageFolder(uikitConfig.package);
} catch (ex) {
logger.warning(
`Could not find uikit with package name ${uikitConfig.package}. Did you add it to the 'dependencies' section in your 'package.json' file?`
);
return;
}
Comment on lines +33 to +41
Copy link
Contributor

@JosefBredereck JosefBredereck Aug 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide an example patternlab-config.json for that or change the given ones. The user shouldn't get warnings for a freshly installed pattern-lab after we merge this.

Most Important

  • packages/core/patternlab-config.json (used within getDefaultConfig)
  • packages/edition-node/patternlab-config.json
  • packages/edition-node-gulp/patternlab-config.json
  • packages/edition-twig/patternlab-config.json

Less Important or Internal

  • packages/core/test/util/patternlab-config.json
  • packages/cli/test/fixtures/patternlab-config.json
  • packages/development-edition-engine-handlebars/patternlab-config.json
  • packages/development-edition-engine-react/patternlab-config.json
  • packages/development-edition-engine-twig/patternlab-config.json

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

packages/core/test/util/patternlab-config.json is left as is intentionally because it is used in the tests for checking the warning messages.

Question back: packages/development-edition-engine-react/patternlab-config.json doesn't have a uikits block, but does point to ./node_modules/@pattern-lab/uikit-workshop files inside the paths section. With my change, this won't work in Yarn v2. I don't know if this is anything specific to React but I would need some help here on what to do.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave it out then. I'm not shure which engines are used anymore. Some feel depreacated / outdated anyway.

} else {
// For backwards compatibility, name to package calculation is:
// 1. name -> name
// 2. name -> uikit-name
// 3. name -> @pattern-lab/name
// 4. name -> @pattern-lab/uikit-name
for (const packageName of [
uikitConfig.name,
`uikit-${uikitConfig.name}`,
`@pattern-lab/${uikitConfig.name}`,
`@pattern-lab/uikit-${uikitConfig.name}`,
]) {
try {
uikitLocation = resolvePackageFolder(packageName); // [2]
} catch (ex) {
// Ignore
}
if (uikitLocation != null) {
uikitConfig.package = packageName;
logger.info(`Found uikit package ${packageName}`);
break;
}
}
if (uikitLocation == null) {
logger.warning(
`Could not find uikit with package name ${uikitConfig.name}, uikit-${uikitConfig.name}, @pattern-lab/${uikitConfig.name} or @pattern-lab/uikit-${uikitConfig.name} defined within patternlab-config.json in the package dependencies.`
);
return;
} else {
logger.warning(
`Please update the configuration of UIKit ${uikitConfig.name} with property 'package: ${uikitConfig.package}' in patternlab-config.json. Lookup by 'name' is deprecated and will be removed in the future.`
);
} // [3]
}

try {
patternlab.uikits[`uikit-${kit.name}`] = {
name: `uikit-${kit.name}`,
modulePath: kit.modulePath,
patternlab.uikits[uikitConfig.name] = {
name: uikitConfig.name,
package: uikitConfig.package,
modulePath: uikitLocation,
enabled: true,
outputDir: configEntry.outputDir,
excludedPatternStates: configEntry.excludedPatternStates,
excludedTags: configEntry.excludedTags,
outputDir: uikitConfig.outputDir,
excludedPatternStates: uikitConfig.excludedPatternStates,
excludedTags: uikitConfig.excludedTags,
header: readModuleFile(
kit,
uikitLocation,
paths.source.patternlabFiles['general-header']
),
footer: readModuleFile(
kit,
uikitLocation,
paths.source.patternlabFiles['general-footer']
),
patternSection: readModuleFile(
kit,
uikitLocation,
paths.source.patternlabFiles.patternSection
),
patternSectionSubType: readModuleFile(
kit,
uikitLocation,
paths.source.patternlabFiles.patternSectionSubtype
),
viewAll: readModuleFile(kit, paths.source.patternlabFiles.viewall),
viewAll: readModuleFile(
uikitLocation,
paths.source.patternlabFiles.viewall
),
}; // [4]
} catch (ex) {
logger.error(ex);
logger.error(
'\nERROR: missing an essential file from ' +
kit.modulePath +
uikitLocation +
paths.source.patternlabFiles +
". Pattern Lab won't work without this file.\n"
);
Expand Down
33 changes: 33 additions & 0 deletions packages/core/src/lib/resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

const path = require('path');

/**
* @func resolveFileInPackage
* Resolves a file inside a package
*/
const resolveFileInPackage = (packageName, ...pathElements) => {
return require.resolve(path.join(packageName, ...pathElements));
};

/**
* @func resolveDirInPackage
* Resolves a file inside a package
*/
const resolveDirInPackage = (packageName, ...pathElements) => {
return path.dirname(resolveFileInPackage(packageName, ...pathElements));
};

/**
* @func resolvePackageFolder
* Resolves the location of a package on disc
*/
const resolvePackageFolder = packageName => {
return path.dirname(resolveFileInPackage(packageName, 'package.json'));
};
Comment on lines +9 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question for this. The whole concept is working without process.cwd() is that correct?
When it tries to resolve the given files/directories it will walk from the resolver location through the filesystem or where would it start?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patternlab loads files from installed NodeJS packages. It starts loading via whatever resolver a package manager could configure inside the Node runtime. In my case, I want to support Yarn v2 with PnP active eventually. In such a setup, no node_modules folder is used at all and every package is stored as a zip file. Here is an example how files inside a package are to be found:

https://yarnpkg.com/features/pnp#packages-are-stored-inside-zip-archives-how-can-i-access-their-files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it does not interfere with other resolvers like npm or yarn v1 everything is fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JosefBredereck if uikit resolution works via require.resolve, the updated code ought to work under any other setup. If it doesn't it is a bug and needs to be fixed, which I'm glad to provide a fix for.


module.exports = {
resolveFileInPackage,
resolveDirInPackage,
resolvePackageFolder,
};
2 changes: 1 addition & 1 deletion packages/core/src/lib/starterkit_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const starterkit_manager = function(config) {
kitDirStats = fs.statSync(kitPath);
} catch (ex) {
logger.warning(
`${starterkitName} not found, use npm to install it first.`
`${starterkitName} not found, use npm or another package manager to install it first.`
);
logger.warning(`${starterkitName} not loaded.`);
return;
Expand Down
Loading