@lwc/compiler
Advanced tools
Comparing version 6.6.3 to 7.0.0-alpha.0
@@ -214,3 +214,5 @@ /** | ||
try { | ||
result = templateCompiler.compile(src, { | ||
result = templateCompiler.compile(src, filename, { | ||
name, | ||
namespace, | ||
experimentalDynamicDirective, | ||
@@ -237,98 +239,11 @@ // TODO [#3370]: remove experimental template expression flag | ||
const warnings = result.warnings.filter((_) => _.level === errors.DiagnosticLevel.Warning); | ||
// TODO [#3733]: remove support for legacy scope tokens | ||
const { scopeToken, legacyScopeToken } = generateScopeTokens(filename, namespace, name); | ||
// Rollup only cares about the mappings property on the map. Since producing a source map for | ||
// the template doesn't make sense, the transform returns an empty mappings. | ||
return { | ||
code: serialize(result.code, filename, scopeToken, legacyScopeToken, apiVersion), | ||
code: result.code, | ||
map: { mappings: '' }, | ||
warnings, | ||
cssScopeTokens: [ | ||
scopeToken, | ||
`${scopeToken}-host`, // implicit scope token created by `makeHostToken()` in `@lwc/engine-core` | ||
// The legacy tokens must be returned as well since we technically don't know what we're going to render | ||
// This is not strictly required since this is only used for Jest serialization (as of this writing), | ||
// and people are unlikely to set runtime flags in Jest, but it is technically correct to include this. | ||
legacyScopeToken, | ||
`${legacyScopeToken}-host`, | ||
], | ||
cssScopeTokens: result.cssScopeTokens, | ||
}; | ||
} | ||
// The reason this hash code implementation [1] is chosen is because: | ||
// 1. It has a very low hash collision rate - testing a list of 466,551 English words [2], it generates no collisions | ||
// 2. It is fast - it can hash those 466k words in 70ms (Node 16, 2020 MacBook Pro) | ||
// 3. The output size is reasonable (32-bit - this can be base-32 encoded at 10-11 characters) | ||
// | ||
// Also note that the reason we're hashing rather than generating a random number is because | ||
// we want the output to be predictable given the input, which helps with caching. | ||
// | ||
// [1]: https://stackoverflow.com/a/52171480 | ||
// [2]: https://github.com/dwyl/english-words/blob/a77cb15f4f5beb59c15b945f2415328a6b33c3b0/words.txt | ||
function generateHashCode(str) { | ||
const seed = 0; | ||
let h1 = 0xdeadbeef ^ seed; | ||
let h2 = 0x41c6ce57 ^ seed; | ||
for (let i = 0, ch; i < str.length; i++) { | ||
ch = str.charCodeAt(i); | ||
h1 = Math.imul(h1 ^ ch, 2654435761); | ||
h2 = Math.imul(h2 ^ ch, 1597334677); | ||
} | ||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); | ||
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); | ||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); | ||
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); | ||
return 4294967296 * (2097151 & h2) + (h1 >>> 0); | ||
} | ||
function escapeScopeToken(input) { | ||
// Minimal escape for strings containing the "@" and "#" characters, which are disallowed | ||
// in certain cases in attribute names | ||
return input.replace(/@/g, '___at___').replace(/#/g, '___hash___'); | ||
} | ||
function generateScopeTokens(filename, namespace, name) { | ||
const uniqueToken = `${namespace}-${name}_${path__namespace.basename(filename, path__namespace.extname(filename))}`; | ||
// This scope token is all lowercase so that it works correctly in case-sensitive namespaces (e.g. SVG). | ||
// It is deliberately designed to discourage people from relying on it by appearing somewhat random. | ||
// (But not totally random, because it's nice to have stable scope tokens for our own tests.) | ||
// Base-32 is chosen because it is not case-sensitive (0-v), and generates short strings with the given hash | ||
// code implementation (10-11 characters). | ||
const hashCode = generateHashCode(uniqueToken); | ||
const scopeToken = `lwc-${hashCode.toString(32)}`; | ||
// This scope token is based on the namespace and name, and contains a mix of uppercase/lowercase chars | ||
const legacyScopeToken = escapeScopeToken(uniqueToken); | ||
return { | ||
scopeToken, | ||
legacyScopeToken, | ||
}; | ||
} | ||
function serialize(code, filename, scopeToken, legacyScopeToken, apiVersion) { | ||
const cssRelPath = `./${path__namespace.basename(filename, path__namespace.extname(filename))}.css`; | ||
const scopedCssRelPath = `./${path__namespace.basename(filename, path__namespace.extname(filename))}.scoped.css`; | ||
let buffer = ''; | ||
buffer += `import { freezeTemplate } from "lwc";\n\n`; | ||
buffer += `import _implicitStylesheets from "${cssRelPath}";\n\n`; | ||
buffer += `import _implicitScopedStylesheets from "${scopedCssRelPath}?scoped=true";\n\n`; | ||
buffer += code; | ||
buffer += '\n\n'; | ||
buffer += 'if (_implicitStylesheets) {\n'; | ||
buffer += ` tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets);\n`; | ||
buffer += `}\n`; | ||
buffer += 'if (_implicitScopedStylesheets) {\n'; | ||
buffer += ` tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets);\n`; | ||
buffer += `}\n`; | ||
if (shared.isAPIFeatureEnabled(0 /* APIFeature.LOWERCASE_SCOPE_TOKENS */, apiVersion)) { | ||
// Include both the new and legacy tokens, so that the runtime can decide based on a flag whether | ||
// we need to render the legacy one. This is designed for cases where the legacy one is required | ||
// for backwards compat (e.g. global stylesheets that rely on the legacy format for a CSS selector). | ||
buffer += `tmpl.stylesheetToken = "${scopeToken}";\n`; | ||
buffer += `tmpl.legacyStylesheetToken = "${legacyScopeToken}";\n`; | ||
} | ||
else { | ||
// In old API versions, we can just keep doing what we always did | ||
buffer += `tmpl.stylesheetToken = "${legacyScopeToken}";\n`; | ||
} | ||
// Note that `renderMode` and `slots` are already rendered in @lwc/template-compiler and appear | ||
// as `code` above. At this point, no more expando props should be added to `tmpl`. | ||
buffer += 'freezeTemplate(tmpl);\n'; | ||
return buffer; | ||
} | ||
@@ -499,3 +414,3 @@ /* | ||
/** The version of LWC being used. */ | ||
const version = "6.6.3"; | ||
const version = "7.0.0-alpha.0"; | ||
@@ -505,3 +420,3 @@ exports.transform = transform; | ||
exports.version = version; | ||
/** version: 6.6.3 */ | ||
/** version: 7.0.0-alpha.0 */ | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -189,3 +189,5 @@ /** | ||
try { | ||
result = compile(src, { | ||
result = compile(src, filename, { | ||
name, | ||
namespace, | ||
experimentalDynamicDirective, | ||
@@ -212,98 +214,11 @@ // TODO [#3370]: remove experimental template expression flag | ||
const warnings = result.warnings.filter((_) => _.level === DiagnosticLevel.Warning); | ||
// TODO [#3733]: remove support for legacy scope tokens | ||
const { scopeToken, legacyScopeToken } = generateScopeTokens(filename, namespace, name); | ||
// Rollup only cares about the mappings property on the map. Since producing a source map for | ||
// the template doesn't make sense, the transform returns an empty mappings. | ||
return { | ||
code: serialize(result.code, filename, scopeToken, legacyScopeToken, apiVersion), | ||
code: result.code, | ||
map: { mappings: '' }, | ||
warnings, | ||
cssScopeTokens: [ | ||
scopeToken, | ||
`${scopeToken}-host`, // implicit scope token created by `makeHostToken()` in `@lwc/engine-core` | ||
// The legacy tokens must be returned as well since we technically don't know what we're going to render | ||
// This is not strictly required since this is only used for Jest serialization (as of this writing), | ||
// and people are unlikely to set runtime flags in Jest, but it is technically correct to include this. | ||
legacyScopeToken, | ||
`${legacyScopeToken}-host`, | ||
], | ||
cssScopeTokens: result.cssScopeTokens, | ||
}; | ||
} | ||
// The reason this hash code implementation [1] is chosen is because: | ||
// 1. It has a very low hash collision rate - testing a list of 466,551 English words [2], it generates no collisions | ||
// 2. It is fast - it can hash those 466k words in 70ms (Node 16, 2020 MacBook Pro) | ||
// 3. The output size is reasonable (32-bit - this can be base-32 encoded at 10-11 characters) | ||
// | ||
// Also note that the reason we're hashing rather than generating a random number is because | ||
// we want the output to be predictable given the input, which helps with caching. | ||
// | ||
// [1]: https://stackoverflow.com/a/52171480 | ||
// [2]: https://github.com/dwyl/english-words/blob/a77cb15f4f5beb59c15b945f2415328a6b33c3b0/words.txt | ||
function generateHashCode(str) { | ||
const seed = 0; | ||
let h1 = 0xdeadbeef ^ seed; | ||
let h2 = 0x41c6ce57 ^ seed; | ||
for (let i = 0, ch; i < str.length; i++) { | ||
ch = str.charCodeAt(i); | ||
h1 = Math.imul(h1 ^ ch, 2654435761); | ||
h2 = Math.imul(h2 ^ ch, 1597334677); | ||
} | ||
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507); | ||
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); | ||
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); | ||
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); | ||
return 4294967296 * (2097151 & h2) + (h1 >>> 0); | ||
} | ||
function escapeScopeToken(input) { | ||
// Minimal escape for strings containing the "@" and "#" characters, which are disallowed | ||
// in certain cases in attribute names | ||
return input.replace(/@/g, '___at___').replace(/#/g, '___hash___'); | ||
} | ||
function generateScopeTokens(filename, namespace, name) { | ||
const uniqueToken = `${namespace}-${name}_${path.basename(filename, path.extname(filename))}`; | ||
// This scope token is all lowercase so that it works correctly in case-sensitive namespaces (e.g. SVG). | ||
// It is deliberately designed to discourage people from relying on it by appearing somewhat random. | ||
// (But not totally random, because it's nice to have stable scope tokens for our own tests.) | ||
// Base-32 is chosen because it is not case-sensitive (0-v), and generates short strings with the given hash | ||
// code implementation (10-11 characters). | ||
const hashCode = generateHashCode(uniqueToken); | ||
const scopeToken = `lwc-${hashCode.toString(32)}`; | ||
// This scope token is based on the namespace and name, and contains a mix of uppercase/lowercase chars | ||
const legacyScopeToken = escapeScopeToken(uniqueToken); | ||
return { | ||
scopeToken, | ||
legacyScopeToken, | ||
}; | ||
} | ||
function serialize(code, filename, scopeToken, legacyScopeToken, apiVersion) { | ||
const cssRelPath = `./${path.basename(filename, path.extname(filename))}.css`; | ||
const scopedCssRelPath = `./${path.basename(filename, path.extname(filename))}.scoped.css`; | ||
let buffer = ''; | ||
buffer += `import { freezeTemplate } from "lwc";\n\n`; | ||
buffer += `import _implicitStylesheets from "${cssRelPath}";\n\n`; | ||
buffer += `import _implicitScopedStylesheets from "${scopedCssRelPath}?scoped=true";\n\n`; | ||
buffer += code; | ||
buffer += '\n\n'; | ||
buffer += 'if (_implicitStylesheets) {\n'; | ||
buffer += ` tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitStylesheets);\n`; | ||
buffer += `}\n`; | ||
buffer += 'if (_implicitScopedStylesheets) {\n'; | ||
buffer += ` tmpl.stylesheets.push.apply(tmpl.stylesheets, _implicitScopedStylesheets);\n`; | ||
buffer += `}\n`; | ||
if (isAPIFeatureEnabled(0 /* APIFeature.LOWERCASE_SCOPE_TOKENS */, apiVersion)) { | ||
// Include both the new and legacy tokens, so that the runtime can decide based on a flag whether | ||
// we need to render the legacy one. This is designed for cases where the legacy one is required | ||
// for backwards compat (e.g. global stylesheets that rely on the legacy format for a CSS selector). | ||
buffer += `tmpl.stylesheetToken = "${scopeToken}";\n`; | ||
buffer += `tmpl.legacyStylesheetToken = "${legacyScopeToken}";\n`; | ||
} | ||
else { | ||
// In old API versions, we can just keep doing what we always did | ||
buffer += `tmpl.stylesheetToken = "${legacyScopeToken}";\n`; | ||
} | ||
// Note that `renderMode` and `slots` are already rendered in @lwc/template-compiler and appear | ||
// as `code` above. At this point, no more expando props should be added to `tmpl`. | ||
buffer += 'freezeTemplate(tmpl);\n'; | ||
return buffer; | ||
} | ||
@@ -474,6 +389,6 @@ /* | ||
/** The version of LWC being used. */ | ||
const version = "6.6.3"; | ||
const version = "7.0.0-alpha.0"; | ||
export { transform, transformSync, version }; | ||
/** version: 6.6.3 */ | ||
/** version: 7.0.0-alpha.0 */ | ||
//# sourceMappingURL=index.js.map |
@@ -18,4 +18,24 @@ # LWC core license | ||
MIT license defined in package.json in v0.4.0. | ||
The MIT License (MIT) | ||
Copyright © 2024 James Garbutt | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the “Software”), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
## entities | ||
@@ -22,0 +42,0 @@ |
@@ -7,3 +7,3 @@ { | ||
"name": "@lwc/compiler", | ||
"version": "6.6.3", | ||
"version": "7.0.0-alpha.0", | ||
"description": "LWC compiler", | ||
@@ -46,3 +46,3 @@ "keywords": [ | ||
"dependencies": { | ||
"@babel/core": "7.24.4", | ||
"@babel/core": "7.24.5", | ||
"@babel/plugin-transform-async-generator-functions": "7.24.3", | ||
@@ -53,9 +53,9 @@ "@babel/plugin-transform-async-to-generator": "7.24.1", | ||
"@locker/babel-plugin-transform-unforgeables": "0.20.0", | ||
"@lwc/babel-plugin-component": "6.6.3", | ||
"@lwc/errors": "6.6.3", | ||
"@lwc/shared": "6.6.3", | ||
"@lwc/ssr-compiler": "6.6.3", | ||
"@lwc/style-compiler": "6.6.3", | ||
"@lwc/template-compiler": "6.6.3" | ||
"@lwc/babel-plugin-component": "7.0.0-alpha.0", | ||
"@lwc/errors": "7.0.0-alpha.0", | ||
"@lwc/shared": "7.0.0-alpha.0", | ||
"@lwc/ssr-compiler": "7.0.0-alpha.0", | ||
"@lwc/style-compiler": "7.0.0-alpha.0", | ||
"@lwc/template-compiler": "7.0.0-alpha.0" | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
69472
1001
1
+ Added@babel/core@7.24.5(transitive)
+ Added@lwc/babel-plugin-component@7.0.0-alpha.0(transitive)
+ Added@lwc/errors@7.0.0-alpha.0(transitive)
+ Added@lwc/shared@7.0.0-alpha.0(transitive)
+ Added@lwc/ssr-compiler@7.0.0-alpha.0(transitive)
+ Added@lwc/style-compiler@7.0.0-alpha.0(transitive)
+ Added@lwc/template-compiler@7.0.0-alpha.0(transitive)
- Removed@babel/core@7.24.4(transitive)
- Removed@lwc/babel-plugin-component@6.6.3(transitive)
- Removed@lwc/errors@6.6.3(transitive)
- Removed@lwc/shared@6.6.3(transitive)
- Removed@lwc/ssr-compiler@6.6.3(transitive)
- Removed@lwc/style-compiler@6.6.3(transitive)
- Removed@lwc/template-compiler@6.6.3(transitive)
Updated@babel/core@7.24.5
Updated@lwc/errors@7.0.0-alpha.0
Updated@lwc/shared@7.0.0-alpha.0