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

import new tags and functions from 6.1.0.235-RC #1444

Merged
merged 17 commits into from
Jul 8, 2024
Merged
2 changes: 1 addition & 1 deletion .github/scripts/generate-index-recipes.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ async function generateIndex() {
await fs.writeJson(outputPath, index, { spaces: 2 });

console.log(`Writing README to ${readmePath}`);
await fs.writeFile(readmePath, readmeContent, 'utf-8');
await fs.writeFile(readmePath, readmeContent.trim(), 'utf-8');

const readmeExists = await fs.pathExists(readmePath);
console.log(`README exists: ${readmeExists}`);
Expand Down
44 changes: 22 additions & 22 deletions .github/workflows/index-recipes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@ name: Generate Recipes Index
on:
push:
branches:
- '**' # This will trigger on push to any branch
- "**"
paths:
- 'docs/recipes/**'
- "docs/recipes/**"
workflow_dispatch:

jobs:
generate-index:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '14'

- name: Install dependencies
run: |
npm install fs-extra
- name: Install dependencies
run: |
npm install fs-extra

- name: Generate index
run: |
node .github/scripts/generate-index-recipes.js
- name: Generate index
run: |
node .github/scripts/generate-index-recipes.js

- name: Commit and push changes
run: |
BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add docs/recipes/index.json docs/recipes/README.md
git commit -m "Update recipes index and README"
git push origin $BRANCH_NAME
- name: Commit and push changes
run: |
BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add docs/recipes/index.json docs/recipes/README.md
git commit -m "Update recipes index and README"
git push origin $BRANCH_NAME
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
with:
webroot: ${{ github.workspace }}
execute: /build-all.cfm
luceeVersion: 6.1.0.217-SNAPSHOT
luceeVersion: 6.1.0.235-RC
# redis, chart, lucene, form. ajax, chart
extensions: 60772C12-F179-D555-8E2CD2B4F7428718;version=3.0.0.54-SNAPSHOT,D46B46A9-A0E3-44E1-D972A04AC3A8DC10,EFDEB172-F52E-4D84-9CD1A1F561B3DFC8,FAD67145-E3AE-30F8-1C11A6CCF544F0B7,6E2CB28F-98FB-4B51-B6BE6C64ADF35473,DF28D0A4-6748-44B9-A2FDC12E4E2E4D38
- name: Upload Artifact
Expand Down
57 changes: 33 additions & 24 deletions api/data/DocTree.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,28 @@ component accessors=true {

private void function _initializeEmptyTree() {
setTree( [] );
setIdMap( {} );
setPathMap( {} );
setPageTypeMap( {} );
setRelatedMap( {} );
setCategoryMap( {} );
setReferenceMap( {} );
setDirectlyRelatedMap( {} );
setIdMap( [:] );
setPathMap( [:] );
setPageTypeMap( [:] );
setRelatedMap( [:] );
setCategoryMap( [:] );
setReferenceMap( [:] );
setDirectlyRelatedMap( [:] );
}

public void function updateTree() {
_updateTree();
}

public any function getPage( required string id ) {
if ( !pageExists( arguments.id ) )
systemOutput( "GetPage: #id# does not exist in doctree", true );
return variables.idMap[ arguments.id ] ?: NullValue();
}

public any function getPageByPath( required string path ) {
if ( !structKeyExists( variables.pathMap, arguments.path ) )
systemOutput( "GetPageByPath: #path# does not exist in doctree", true );
return variables.pathMap[ arguments.path ] ?: NullValue();
}

Expand Down Expand Up @@ -206,16 +210,19 @@ component accessors=true {
var start = getTickCount();
var _threads = getThreads();
each (q_source_files, function (page) {
// systemOutput( arguments.page.path & arguments.page.name, true);
var _parsedPage = new PageReader().preparePageObject( variables.rootDir, arguments.page.name, arguments.page.directory, arguments.page.path );

if ( ! _parsedPage.getHidden() ) {
variables.pageCache.addPage(
_parsedPage,
arguments.page.path
_parsedPage.getPath()
);
} else {
// systemOutput("hidden--------------------#arguments.page.path#", true)
}
}, (_threads != 1), _threads);
request.logger (text="Pages Parsed in #(getTickCount()-start)/1000#s");
request.logger (text=" #len(variables.pageCache.getPages())# Pages Parsed in #(getTickCount()-start)/1000#s");

_buildTreeHierachy(false);
_parseTree();
Expand Down Expand Up @@ -292,16 +299,22 @@ component accessors=true {
private void function _parseTree( ) {
// expose guides as a top level folder
for (var folder in variables.tree){
if (folder.getId() eq "guides"){
var guideTree = folder.getChildren();
for (var guide in guideTree){
if (guide.getForceSortOrder() gt 0){
guide.setSortOrder(guide.getForceSortOrder());
} else {
guide.setSortOrder(6 + NumberFormat(guide.getSortOrder()/100,"0.00"));
switch( folder.getId() ){
case "guides":
var guideTree = folder.getChildren();
for (var guide in guideTree){
if (guide.getForceSortOrder() gt 0){
guide.setSortOrder(guide.getForceSortOrder());
} else {
guide.setSortOrder(6 + NumberFormat(guide.getSortOrder()/100,"0.00"));
}
variables.tree.append(guide);
}
variables.tree.append(guide);
}
break;
/*
case "recipes":
break;
*/
}
}
_sortChildren( variables.tree );
Expand Down Expand Up @@ -332,12 +345,8 @@ component accessors=true {
variables.tree.append( arguments.page );
}

if ( !isPage ){
if ( page.getPath() comtains "/recipes" ){
request.logger(text="skipping coz /recipes" );
return;
}
throw "not a page [#page.path#]"; // only add main pages
if ( !isPage ){
throw "not a page [#page.getFilePath()#]"; // only add main pages
}

if ( !StructKeyExists( variables.pageTypeMap, pageType ) )
Expand Down
11 changes: 10 additions & 1 deletion api/data/Page.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ component accessors=true {
}

public string function getPageMenuTitle(){
if (len(getMenuTitle()) gt 0)
if ( len( getMenuTitle() ) gt 0 )
return getMenuTitle();
else
return getTitle();
Expand Down Expand Up @@ -110,4 +110,13 @@ component accessors=true {
return "[[object-#type#]]";
}
}

public function getInstance(){
var st = {};
for ( var v in variables ){
if ( !isNull(variables[ v ]) && isSimpleValue( variables[ v ] ) and len( variables[v] ) lt 75 )
st[v ] = variables[ v ];
}
return st;
}
}
3 changes: 2 additions & 1 deletion api/data/PageCache.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ component accessors=true {
local.q_files = QueryNew("name,directory,depth,src,dateLastModified,fullpath", "varchar,varchar,numeric,varchar,date,varchar");
var timestamp = CreateDate(2000,1,1);//
for( var file in local.files){
var row = QueryAddRow(local.q_files);
file = _removeRootDirectoryFromFilePath(file);
if ( ListFirst( file, "/" ) eq "recipes") continue;
var row = QueryAddRow(local.q_files);
querySetCell(local.q_files, "name", ListLast(file, "/") , row);
querySetCell(local.q_files, "fullpath", file , row);
querySetCell(local.q_files, "directory", GetDirectoryFromPath(file) , row);
Expand Down
70 changes: 64 additions & 6 deletions api/data/PageReader.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,32 @@ component {
}
}

page.setPath( arguments.pagePath );
// hack to restructure recipes as docs content
if ( listFirst( page.getPath(), "/" ) eq "recipes" ){
page.setSlug( page.getPageType() )

if (page.getPageType() eq "README"){
page.setPath( page.getPath() );
page.setPageType( "listing" );
page.setVisible( true );
page.setReference( false );
page.setBody( "Recipes" );
page.setTitle( "Lucee Recipes" );
page.setDescription( "Lucee Recipes" );
} else {
page.setPath( page.getPath() & "/" & replace( page.getPageType(), ".md", "" ) );
page.setPageType( "page" );
}
} else {
page.setPath( arguments.pagePath );
}

if ( !page.getId().len() ) {
page.setId( page.getPath() );
}

page.setChildren( [] );
page.setDepth( ListLen( page.getPath(), "/" ) );

return page;
}

Expand All @@ -74,7 +92,7 @@ component {
var slug = ListLast( arguments.pageDir, "\/" );

var fileContent = FileReadAsUnix( path );
var data = _parsePage( fileContent );
var data = _parsePage( fileContent, path );
var sortOrder = "";

// if the last directory is in the format 00.home, flag is as visible
Expand Down Expand Up @@ -118,22 +136,24 @@ component {
public any function readPageFileSource( required string filePath ) {
var path = Replace(arguments.filePath,"\","/","all");
var fileContent = FileReadAsUnix( path );
var data = _parsePage( fileContent );
var data = _parsePage( fileContent, arguments.filePath );
return data;
}

private struct function _parsePage( required string pageContent ) {
private struct function _parsePage( required string pageContent, required string filePath ) {
var yamlAndBody = _splitYamlAndBody( arguments.pageContent );
var parsed = { body = yamlAndBody.body };

if ( yamlAndBody.yaml.len() ) {
parsed.append( _parseYaml( yamlAndBody.yaml ), false );
} else if ( len( trim( arguments.pageContent ) ) ){
parsed = _splitCommentStructAndBody( arguments.pageContent, arguments.filePath );
}

return parsed;
}

private struct function _splitYamlAndBody( required string pageContent ) {
private struct function _splitYamlAndBody( required string pageContent, string filePath ) {
var splitterRegex = "^(\-\-\-\n(.*?)\n\-\-\-\n)?(.*)$";

return {
Expand All @@ -142,6 +162,44 @@ component {
}
}

private struct function _splitCommentStructAndBody( required string pageContent, string filePath ) {
// recipies use a different format, json in html comments
/*

<!--
{
{
"title": "XML Fast And Easy, using SAX - Listener Functions",
"id": "xml-fast-and-easy",
"related": [
"function-xmlparse"
],
}
--->
*/
var str = trim( arguments.pageContent );
var startComment = find("<!--", str, 1);
if ( startComment != 1 ){
return { body: arguments.pageContent };
//throw "missing opening html comment metadata [#arguments.filePath#]";
}
var endComment = find( "-->", str, startComment );
if ( endComment == 0 )
throw "missing closing html comment metadata [#arguments.filePath#]";
var meta = mid( str, 5, endComment - 5 );
//systemOutput( "!!" & meta & "!!", true );
if ( !isJson( meta ) ){
throw "metadata is not json [#arguments.filePath#]";
}
var body = mid( str, endComment + 3 );
if ( len( trim( body ) ) eq 0 )
throw "empty content after metadata [#arguments.filePath#]";
return {
yaml = deserializeJson( meta )
, body = body
}
}

private string function _convertToUnixLineEnding( required string content ){
return REReplace(arguments.content, "\r\n", chr(10), "all");
}
Expand Down
12 changes: 10 additions & 2 deletions api/rendering/SyntaxHighlighter.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ component {
} else if ( arguments.language.reFindNoCase( "^(lucee|cfm|coldfusion)" ) ) {
arguments.language = "cfm";
}

var highlighted = highlighter.highlight( arguments.code, arguments.language, false );
lock name="highlight" type="exclusive" timeout=10 {
try {
var highlighted = highlighter.highlight( arguments.code, arguments.language, false );
} catch (e ){

systemOutput( arguments, true );
//systemOutput( e );
highlighted = arguments.code;
}
}

if ( useTryCf ) {
var rawCode = '<script type="text/template" id="code-#LCase( Hash( highlighted ) )#" data-trycf="true" data-script="#( arguments.language == 'cfs' )#">'
Expand Down
2 changes: 1 addition & 1 deletion build-all.cfm
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
if ( fileExists( docsZipFile ) )
fileDelete( docsZipFile );
if (directoryExists( "builds/artifacts") ){
directoryDelete(" builds/artifacts", true);
directoryDelete("builds/artifacts", true);
}
include template="import.cfm";
include template="build.cfm";
Expand Down
2 changes: 1 addition & 1 deletion builders/html/Builder.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ component {
links.append( variables._getTestCasesLink(name) );
break;
default:
break;
break;
}
}
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Used in conjunction with the 'hash' type, this numeric input contributes to the generation of a deterministic ULID by influencing its random component.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Similar to 'input1', this string input is utilized only in the 'hash' mode to further seed the ULID's random component, enabling the creation of a deterministic ULID based on the hash of the inputs.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Specifies the generation mode of the ULID. If not defined, a standard ULID is generated. 'monotonic' ensures ULIDs increase monotonically, suitable for ensuring order in rapid generation scenarios. 'hash' mode generates a ULID based on hashing the provided inputs, useful for creating deterministic identifiers.
Empty file.
Empty file.
8 changes: 8 additions & 0 deletions docs/03.reference/01.functions/createulid/function.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: createULID
id: function-createulid
related:
categories:
---

Generates a ULID (Universally Unique Lexicographically Sortable Identifier), a 128-bit identifier where the first 48 bits are a timestamp representing milliseconds since the Unix Epoch (1970-01-01), ensuring temporal ordering. The remaining 80 bits are populated by a secure random number generator, contributing to the identifier's uniqueness. The output is a 26-character string in its canonical representation. This function can operate in three modes specified by the 'type' argument: 'empty' for standard ULID generation, 'monotonic' to ensure sequential IDs even in rapid succession, and 'hash' to generate a ULID based on hashed input values.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Number of bits to use for the generated Keys.
Empty file.
Empty file.
Loading