Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(engine-twig): twig include function syntax not matched by findPar… #1473

Merged
Merged
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
120 changes: 100 additions & 20 deletions packages/engine-twig/lib/engine_twig.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class TwingLoaderPatternLab {
* @throws TwingErrorLoader When name is not found
*/
getSourceContext(name, from) {
var pattern = this.patterns.get(name);
const pattern = this.patterns.get(name);
return Promise.resolve(
new TwingSource(pattern.extendedTemplate, name, pattern.relPath)
);
Expand Down Expand Up @@ -116,23 +116,23 @@ const fileSystemLoader = new TwingLoaderFilesystem();
const patternLabLoader = new TwingLoaderPatternLab();
const chainLoader = new TwingLoaderChain([fileSystemLoader, patternLabLoader]);
const twing = new TwingEnvironment(chainLoader);
var metaPath;
let metaPath;
let patternLabConfig = {};

var engine_twig = {
const engine_twig = {
engine: twing,
engineName: 'twig',
engineFileExtension: '.twig',

// regexes, stored here so they're only compiled once
findPartialsRE:
/{%[-]?\s*(?:extends|include|embed|from|import|use)\s+('[^']+'|"[^"]+").*?%}/g,
findPartialKeyRE: /"((?:\\.|[^"\\])*)"/,
/{[%{]\s*.*?(?:extends|include|embed|from|import|use)\(?\s*['"](.+?)['"][\s\S]*?\)?\s*[%}]}/g,
findListItemsRE:
/({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // TODO

// render it
renderPattern: function renderPattern(pattern, data, partials) {
var patternPath = pattern.basePattern
let patternPath = pattern.basePattern
? pattern.basePattern.relPath
: pattern.relPath;
if (patternPath.lastIndexOf(metaPath) === 0) {
Expand All @@ -150,8 +150,15 @@ var engine_twig = {

// find and return any {% include 'template-name' %} within pattern
findPartials: function findPartials(pattern) {
var matches = pattern.template.match(this.findPartialsRE);
return matches;
const matches = pattern.template.match(this.findPartialsRE);
const filteredMatches =
matches &&
matches.filter((match) => {
// Filter out programmatically created includes.
// i.e. {% include '@namespace/icons/assets/' ~ name ~ '.svg' %}
return match.indexOf('~') === -1;
});
return filteredMatches;
},

// returns any patterns that match {{> value(foo:"bar") }} or {{>
Expand All @@ -161,18 +168,90 @@ var engine_twig = {
// being implemented here.
return [];
},

findListItems: function (pattern) {
var matches = pattern.template.match(this.findListItemsRE);
const matches = pattern.template.match(this.findListItemsRE);
return matches;
},

// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
findPartial: function (partialString) {
var partial = partialString.match(this.findPartialKeyRE)[0];
partial = partial.replace(/"/g, '');
try {
const partial = partialString.replace(this.findPartialsRE, '$1');

// Check if namespaces is not empty.
const [selectedNamespace] = fileSystemLoader
.getNamespaces()
.filter((namespace) => {
// Check to see if this partial contains within the namespace id.
return partial.indexOf(`@${namespace}`) !== -1;
});

let namespaceResolvedPartial = '';

if (selectedNamespace.length > 0) {
// Loop through all namespaces and try to resolve the namespace to a file path.
const namespacePaths = fileSystemLoader.getPaths(selectedNamespace);

for (let index = 0; index < namespacePaths.length; index++) {
const patternPath = path.isAbsolute(namespacePaths[index])
? path.relative(
patternLabConfig.paths.source.root,
namespacePaths[index]
)
: namespacePaths[index];

// Replace the name space with the actual path.
// i.e. @atoms -> source/_patterns/atoms
const tempPartial = path.join(
process.cwd(),
partial.replace(`@${selectedNamespace}`, patternPath)
);

return partial;
try {
// Check to see if the file actually exists.
if (fs.existsSync(tempPartial)) {
// get the path to the top-level folder of this pattern
// ex. /Users/bradfrost/sites/pattern-lab/packages/edition-twig/source/_patterns/atoms
const fullFolderPath = `${
tempPartial.split(namespacePaths[index])[0]
}${namespacePaths[index]}`;

// then tease out the folder name itself (including the # prefix)
// ex. atoms
const folderName = fullFolderPath.substring(
fullFolderPath.lastIndexOf('/') + 1,
fullFolderPath.length
);

// finally, return the Twig path we created from the full file path
// ex. atoms/buttons/button.twig
const fullIncludePath = tempPartial.replace(
tempPartial.split(
`${folderName}${tempPartial.split(folderName)[1]}`
)[0],
''
);

namespaceResolvedPartial = fullIncludePath;

// After it matches one time, set the resolved partial and exit the loop.
break;
}
} catch (err) {
console.error(err);
}
}
}
// Return the path with the namespace resolved OR the regex'd partial.
return namespaceResolvedPartial || partial;
} catch (err) {
console.error(
'Error occurred when trying to find partial name in: ' + partialString
);
return null;
}
},

spawnFile: function (config, fileName) {
Expand Down Expand Up @@ -209,31 +288,32 @@ var engine_twig = {
* @param {object} config - the global config object from core
*/
usePatternLabConfig: function (config) {
patternLabConfig = config;
metaPath = path.resolve(config.paths.source.meta);
// Global paths
fileSystemLoader.addPath(config.paths.source.meta);
fileSystemLoader.addPath(config.paths.source.patterns);
// Namespaced paths
if (
config['engines'] &&
config['engines']['twig'] &&
config['engines']['twig']['namespaces']
config.engines &&
config.engines.twig &&
config.engines.twig.namespaces
) {
var namespaces = config['engines']['twig']['namespaces'];
const namespaces = config.engines.twig.namespaces;
Object.keys(namespaces).forEach(function (key, index) {
fileSystemLoader.addPath(namespaces[key], key);
});
}

// add twing extensions
if (
config['engines'] &&
config['engines']['twig'] &&
config['engines']['twig']['loadExtensionsFile']
config.engines &&
config.engines.twig &&
config.engines.twig.loadExtensionsFile
) {
const extensionsFile = path.resolve(
'./',
config['engines']['twig']['loadExtensionsFile']
config.engines.twig.loadExtensionsFile
);
if (fs.pathExistsSync(extensionsFile)) {
try {
Expand Down